Skip to content

Commit

Permalink
frontend: Use CallArguments for all call kinds
Browse files Browse the repository at this point in the history
  • Loading branch information
dinfuehr committed Nov 17, 2024
1 parent 7ccac3e commit 4e14137
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 173 deletions.
24 changes: 3 additions & 21 deletions dora-frontend/src/typeck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,12 @@ use crate::typeck::control::{
use crate::typeck::expr::{check_expr, read_ident, read_path, read_path_expr};
pub use crate::typeck::expr::{compute_lit_float, compute_lit_int};
use crate::typeck::function::{
add_local, arg_allows, args_compatible, args_compatible_fct, check_args_compatible,
check_args_compatible_fct, check_lit_char, check_lit_float, check_lit_int, check_lit_str,
is_simple_enum, TypeCheck, VarManager,
add_local, arg_allows, check_args_compatible, check_args_compatible_fct, check_lit_char,
check_lit_float, check_lit_int, check_lit_str, is_simple_enum, TypeCheck, VarManager,
};
use crate::typeck::lookup::find_method_call_candidates;
use crate::typeck::stmt::{check_pattern, check_stmt};
use crate::{ErrorMessage, SourceType, Span};
use crate::{SourceType, Span};

mod call;
mod constck;
Expand Down Expand Up @@ -193,20 +192,3 @@ pub struct CallArguments {
arguments: Vec<Arc<ast::Argument>>,
span: Span,
}

impl CallArguments {
fn assume_all_positional(&self, ck: &TypeCheck) -> Vec<SourceType> {
for arg in &self.arguments {
if arg.name.is_some() {
ck.sa
.report(ck.file_id, arg.span, ErrorMessage::UnexpectedNamedArgument);
}
}

self.arguments
.iter()
.filter(|a| a.name.is_none())
.map(|p| ck.analysis.ty(p.id))
.collect::<Vec<SourceType>>()
}
}
103 changes: 34 additions & 69 deletions dora-frontend/src/typeck/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ use crate::access::{
use crate::interner::Name;
use crate::sema::{
find_field_in_class, find_impl, new_identity_type_params, CallType, ClassDefinitionId,
ElementWithFields, EnumDefinitionId, FctDefinitionId, IdentType, Sema, StructDefinitionId,
TraitDefinition, TypeParamId,
ElementWithFields, EnumDefinitionId, FctDefinitionId, IdentType, Param, Sema,
StructDefinitionId, TraitDefinition, TypeParamId,
};
use crate::specialize::replace_type;
use crate::sym::SymbolKind;
use crate::typeck::{
args_compatible, args_compatible_fct, check_args_compatible_fct, check_expr,
find_method_call_candidates, read_path_expr, CallArguments, TypeCheck,
check_args_compatible, check_args_compatible_fct, check_expr, find_method_call_candidates,
read_path_expr, CallArguments, TypeCheck,
};
use crate::typeparamck;
use crate::{
Expand Down Expand Up @@ -98,7 +98,7 @@ fn check_expr_call_generic_static_method(
e: &ast::ExprCallType,
tp_id: TypeParamId,
name: String,
args: &[SourceType],
arguments: CallArguments,
) -> SourceType {
let mut matched_methods = Vec::new();
let interned_name = ck.sa.interner.intern(&name);
Expand All @@ -124,32 +124,18 @@ fn check_expr_call_generic_static_method(
return ty_error();
}

if args.contains(&ty_error()) {
ck.analysis.set_ty(e.id, ty_error());
return ty_error();
}

let (trait_method_id, trait_ty) = matched_methods.pop().expect("missing method");
let trait_method = ck.sa.fct(trait_method_id);

let tp = SourceType::TypeParam(tp_id);

if !args_compatible_fct(
ck.sa,
check_args_compatible_fct(
ck,
trait_method,
args,
arguments,
&trait_ty.type_params,
Some(tp.clone()),
) {
let fct_params = trait_method
.params_without_self()
.iter()
.map(|a| ck.ty_name(&a.ty()))
.collect::<Vec<_>>();
let arg_types = args.iter().map(|a| ck.ty_name(a)).collect::<Vec<_>>();
let msg = ErrorMessage::ParamTypesIncompatible(name, fct_params, arg_types);
ck.sa.report(ck.file_id, e.span, msg);
}
);

let call_type = CallType::GenericStaticMethod(
tp_id,
Expand Down Expand Up @@ -182,10 +168,8 @@ fn check_expr_call_expr(
return ty_error();
}

let arg_types = arguments.assume_all_positional(ck);

if expr_type.is_lambda() {
return check_expr_call_expr_lambda(ck, e, expr_type, &arg_types);
return check_expr_call_expr_lambda(ck, e, expr_type, arguments);
}

let trait_id = ck.sa.known.traits.index_get();
Expand Down Expand Up @@ -241,20 +225,24 @@ fn check_expr_call_expr_lambda(
ck: &mut TypeCheck,
e: &ast::ExprCallType,
expr_type: SourceType,
arg_types: &[SourceType],
arguments: CallArguments,
) -> SourceType {
let (params, return_type) = expr_type.to_lambda().expect("lambda expected");

// Type params are mapped to themselves.
let type_params_count = ck.type_param_definition.type_param_count();
let type_params = new_identity_type_params(type_params_count);

if !args_compatible(ck.sa, params.types(), false, arg_types, &type_params, None) {
let fct_params = params.iter().map(|a| ck.ty_name(&a)).collect::<Vec<_>>();
let arg_types = arg_types.iter().map(|a| ck.ty_name(a)).collect::<Vec<_>>();
let msg = ErrorMessage::LambdaParamTypesIncompatible(fct_params, arg_types);
ck.sa.report(ck.file_id, e.span, msg);
}
let regular_params = params.iter().map(|p| Param::new_ty(p)).collect::<Vec<_>>();

check_args_compatible(
ck,
regular_params.as_slice(),
None,
arguments,
&type_params,
None,
);

let call_type = CallType::Lambda(params, return_type.clone());

Expand Down Expand Up @@ -374,8 +362,6 @@ fn check_expr_call_method(
fct_type_params: SourceTypeArray,
arguments: CallArguments,
) -> SourceType {
let arg_types = arguments.assume_all_positional(ck);

if let SourceType::TypeParam(id) = object_type {
assert_eq!(fct_type_params.len(), 0);
return check_expr_call_generic_type_param(
Expand All @@ -384,11 +370,11 @@ fn check_expr_call_method(
SourceType::TypeParam(id),
id,
method_name,
&arg_types,
arguments,
);
} else if object_type.is_self() {
assert_eq!(fct_type_params.len(), 0);
return check_expr_call_self(ck, e, method_name, &arg_types);
return check_expr_call_self(ck, e, method_name, arguments);
}

if object_type.is_error() {
Expand Down Expand Up @@ -826,7 +812,7 @@ fn check_expr_call_self(
ck: &mut TypeCheck,
e: &ast::ExprCallType,
name: String,
args: &[SourceType],
arguments: CallArguments,
) -> SourceType {
let mut matched_methods = Vec::new();
let interned_name = ck.sa.interner.intern(&name);
Expand Down Expand Up @@ -865,23 +851,13 @@ fn check_expr_call_self(
CallType::Method(SourceType::This, trait_method_id, trait_type_params.clone());
ck.analysis.map_calls.insert(e.id, Arc::new(call_type));

if !args_compatible_fct(
ck.sa,
check_args_compatible_fct(
ck,
trait_method,
args,
arguments,
&trait_type_params,
Some(SourceType::This),
) {
let trait_params = trait_method
.params_without_self()
.iter()
.map(|a| specialize_type(ck.sa, a.ty(), &trait_type_params))
.map(|a| ck.ty_name(&a))
.collect::<Vec<String>>();
let param_names = args.iter().map(|a| ck.ty_name(a)).collect::<Vec<String>>();
let msg = ErrorMessage::ParamTypesIncompatible(name, trait_params, param_names);
ck.sa.report(ck.file_id, e.span, msg);
}
);

return_type
} else {
Expand Down Expand Up @@ -921,7 +897,7 @@ fn check_expr_call_generic_type_param(
object_type: SourceType,
id: TypeParamId,
name: String,
args: &[SourceType],
arguments: CallArguments,
) -> SourceType {
assert!(object_type.is_type_param());
let mut matched_methods = Vec::new();
Expand Down Expand Up @@ -962,23 +938,13 @@ fn check_expr_call_generic_type_param(
);
ck.analysis.map_calls.insert(e.id, Arc::new(call_type));

if !args_compatible_fct(
ck.sa,
check_args_compatible_fct(
ck,
trait_method,
args,
arguments,
&trait_type_params,
Some(object_type.clone()),
) {
let trait_params = trait_method
.params_without_self()
.iter()
.map(|a| specialize_type(ck.sa, a.ty(), &trait_type_params))
.map(|a| ck.ty_name(&a))
.collect::<Vec<String>>();
let param_names = args.iter().map(|a| ck.ty_name(a)).collect::<Vec<String>>();
let msg = ErrorMessage::ParamTypesIncompatible(name, trait_params, param_names);
ck.sa.report(ck.file_id, e.span, msg);
}
);

return_type
} else {
Expand Down Expand Up @@ -1144,8 +1110,7 @@ fn check_expr_call_path(
ck.sa.report(ck.file_id, callee_as_path.lhs.span(), msg);
}

let arg_types = arguments.assume_all_positional(ck);
check_expr_call_generic_static_method(ck, e, id, method_name, &arg_types)
check_expr_call_generic_static_method(ck, e, id, method_name, arguments)
}

Some(SymbolKind::Module(module_id)) => {
Expand Down
3 changes: 0 additions & 3 deletions dora-frontend/src/typeck/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,9 +280,6 @@ fn check_expr_assign_call(ck: &mut TypeCheck, e: &ast::ExprBinType) {
let value_type = check_expr(ck, &e.rhs, SourceType::Any);
ck.analysis.set_ty(e.rhs.id(), value_type.clone());

let mut arg_types = args.assume_all_positional(ck);
arg_types.push(value_type.clone());

let trait_id = ck.sa.known.traits.index_set();
let trait_ty = TraitType::from_trait_id(trait_id);

Expand Down
68 changes: 0 additions & 68 deletions dora-frontend/src/typeck/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,25 +425,6 @@ pub(super) fn add_local(
}
}

pub(super) fn args_compatible_fct(
sa: &Sema,
callee: &FctDefinition,
args: &[SourceType],
type_params: &SourceTypeArray,
self_ty: Option<SourceType>,
) -> bool {
let arg_types = callee.params_without_self();
let variadic_arguments = callee.params.is_variadic();
args_compatible(
sa,
&arg_types.iter().map(|p| p.ty()).collect::<Vec<_>>(),
variadic_arguments,
args,
type_params,
self_ty,
)
}

pub(super) fn check_args_compatible_fct(
ck: &TypeCheck,
callee: &FctDefinition,
Expand Down Expand Up @@ -537,55 +518,6 @@ pub(super) fn check_args_compatible(
}
}

pub(super) fn args_compatible(
sa: &Sema,
fct_arg_types: &[SourceType],
variadic_arguments: bool,
args: &[SourceType],
type_params: &SourceTypeArray,
self_ty: Option<SourceType>,
) -> bool {
let right_number_of_arguments = if variadic_arguments {
fct_arg_types.len() - 1 <= args.len()
} else {
fct_arg_types.len() == args.len()
};

if !right_number_of_arguments {
return false;
}

let (def, rest_ty): (&[SourceType], Option<SourceType>) = if variadic_arguments {
(
&fct_arg_types[0..fct_arg_types.len() - 1],
fct_arg_types.last().cloned(),
)
} else {
(&fct_arg_types, None)
};

for (ind, def_arg) in def.iter().enumerate() {
let def_arg = replace_type(sa, def_arg.clone(), Some(&type_params), self_ty.clone());

if !arg_allows(sa, def_arg, args[ind].clone(), self_ty.clone()) {
return false;
}
}

if let Some(rest_ty) = rest_ty {
let ind = def.len();
let rest_ty = replace_type(sa, rest_ty, Some(&type_params), self_ty.clone());

for expr_ty in &args[ind..] {
if !arg_allows(sa, rest_ty.clone(), expr_ty.clone(), self_ty.clone()) {
return false;
}
}
}

true
}

pub(super) fn arg_allows(
sa: &Sema,
def: SourceType,
Expand Down
17 changes: 5 additions & 12 deletions dora-frontend/src/typeck/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1505,8 +1505,8 @@ fn test_static_method_call_with_type_param() {
err(
"trait X { static fn foo(): Int32; }
fn f[T: X](): Int32 { return T::foo(1i32); }",
(2, 38),
ErrorMessage::ParamTypesIncompatible("foo".into(), Vec::new(), vec!["Int32".into()]),
(2, 45),
ErrorMessage::SuperfluousArgument,
);

ok("trait X { static fn foo(): Int32; }
Expand Down Expand Up @@ -3596,10 +3596,7 @@ fn basic_lambda() {
foo(1i32)
}",
(2, 9),
ErrorMessage::LambdaParamTypesIncompatible(
vec!["Int32".into(), "Int32".into()],
vec!["Int32".into()],
),
ErrorMessage::MissingArguments(2, 1),
);
}

Expand Down Expand Up @@ -3915,12 +3912,8 @@ fn test_generic_trait_method_call() {
t.foo(1, 2);
}
",
(4, 13),
ErrorMessage::ParamTypesIncompatible(
"foo".into(),
vec!["Int64".into()],
vec!["Int64".into(), "Int64".into()],
),
(4, 22),
ErrorMessage::SuperfluousArgument,
);
}

Expand Down

0 comments on commit 4e14137

Please sign in to comment.