diff --git a/dora-frontend/src/specialize.rs b/dora-frontend/src/specialize.rs index 849b52774..1b26de119 100644 --- a/dora-frontend/src/specialize.rs +++ b/dora-frontend/src/specialize.rs @@ -184,7 +184,7 @@ pub fn specialize_ty_for_call( if type_param_ty.is_type_param() { SourceType::GenericAssoc { - tp_id, + tp_id: type_param_ty.type_param_id().expect("missing"), trait_ty, assoc_id, } @@ -527,10 +527,41 @@ pub fn specialize_for_element( | SourceType::Float64 | SourceType::Error => ty, - SourceType::Any - | SourceType::Ptr - | SourceType::Assoc(..) - | SourceType::GenericAssoc { .. } => unreachable!(), + SourceType::GenericAssoc { + tp_id, + trait_ty, + assoc_id, + } => { + let assoc = sa.alias(assoc_id); + assert!(assoc.parent.is_trait()); + let type_param_ty = type_params_for_element[tp_id.index()].clone(); + + if type_param_ty.is_type_param() { + SourceType::GenericAssoc { + tp_id: type_param_ty.type_param_id().expect("missing"), + trait_ty, + assoc_id, + } + } else if let Some(impl_match) = find_impl( + sa, + element, + type_param_ty, + element.type_param_definition(), + trait_ty, + ) { + let impl_ = sa.impl_(impl_match.id); + let ty = impl_ + .trait_alias_map() + .get(&assoc_id) + .map(|a| sa.alias(*a).ty()) + .unwrap_or(SourceType::Error); + specialize_for_element(sa, ty, element, type_params_for_element) + } else { + unimplemented!() + } + } + + SourceType::Any | SourceType::Ptr | SourceType::Assoc(..) => unreachable!(), } } diff --git a/dora-frontend/src/typeck/call.rs b/dora-frontend/src/typeck/call.rs index 420c7ff6c..06d01b6fe 100644 --- a/dora-frontend/src/typeck/call.rs +++ b/dora-frontend/src/typeck/call.rs @@ -135,6 +135,7 @@ fn check_expr_call_generic_static_method( arguments, &trait_ty.type_params, Some(tp.clone()), + |ty| ty, ); let call_type = CallType::GenericStaticMethod( @@ -202,7 +203,7 @@ fn check_expr_call_expr( let method = ck.sa.fct(method_id); - check_args_compatible_fct(ck, method, arguments, &impl_match.bindings, None); + check_args_compatible_fct(ck, method, arguments, &impl_match.bindings, None, |ty| ty); let return_type = specialize_type(ck.sa, method.return_type(), &impl_match.bindings); ck.analysis.set_ty(e.id, return_type.clone()); @@ -243,6 +244,7 @@ fn check_expr_call_expr_lambda( &arguments, &type_params, None, + |ty| ty, ); let call_type = CallType::Lambda(params, return_type.clone()); @@ -278,7 +280,7 @@ fn check_expr_call_fct( ck.file_id, e.span, ) { - check_args_compatible_fct(ck, fct, arguments, &type_params, None); + check_args_compatible_fct(ck, fct, arguments, &type_params, None, |ty| ty); specialize_type(ck.sa, fct.return_type(), &type_params) } else { ty_error() @@ -340,7 +342,7 @@ fn check_expr_call_static_method( ck.file_id, e.span, ) { - check_args_compatible_fct(ck, fct, arguments, &full_type_params, None); + check_args_compatible_fct(ck, fct, arguments, &full_type_params, None, |ty| ty); specialize_type(ck.sa, fct.return_type(), &full_type_params) } else { ty_error() @@ -425,7 +427,7 @@ fn check_expr_call_method( ck.file_id, e.span, ) { - check_args_compatible_fct(ck, fct, arguments, &full_type_params, None); + check_args_compatible_fct(ck, fct, arguments, &full_type_params, None, |ty| ty); let call_data = CallSpecializationData { object_ty: candidate.object_type.clone(), @@ -877,6 +879,7 @@ fn check_expr_call_self( arguments, &trait_type_params, Some(SourceType::This), + |ty| ty, ); return_type @@ -967,6 +970,7 @@ fn check_expr_call_generic_type_param( arguments, &trait_type_params, Some(object_type.clone()), + |ty| specialize_ty_for_generic(ck.sa, ty, id, trait_method.trait_id()), ); return_type diff --git a/dora-frontend/src/typeck/function.rs b/dora-frontend/src/typeck/function.rs index db0689f48..c9f748385 100644 --- a/dora-frontend/src/typeck/function.rs +++ b/dora-frontend/src/typeck/function.rs @@ -419,13 +419,16 @@ pub(super) fn add_local( } } -pub(super) fn check_args_compatible_fct( +pub(super) fn check_args_compatible_fct( ck: &TypeCheck, callee: &FctDefinition, args: CallArguments, type_params: &SourceTypeArray, self_ty: Option, -) { + extra_specialization: S, +) where + S: FnMut(SourceType) -> SourceType, +{ check_args_compatible( ck, callee.params.regular_params(), @@ -433,17 +436,21 @@ pub(super) fn check_args_compatible_fct( &args, type_params, self_ty, + extra_specialization, ); } -pub(super) fn check_args_compatible( +pub(super) fn check_args_compatible( ck: &TypeCheck, regular_params: &[Param], variadic_param: Option<&Param>, args: &CallArguments, type_params: &SourceTypeArray, self_ty: Option, -) { + mut extra_specialization: S, +) where + S: FnMut(SourceType) -> SourceType, +{ for arg in &args.arguments { if let Some(ref name) = arg.name { ck.sa @@ -458,6 +465,7 @@ pub(super) fn check_args_compatible( Some(&type_params), self_ty.clone(), ); + let param_ty = extra_specialization(param_ty); let arg_ty = ck.analysis.ty(arg.id); if !arg_allows(ck.sa, param_ty.clone(), arg_ty.clone(), self_ty.clone()) @@ -522,6 +530,10 @@ pub(super) fn arg_allows( arg: SourceType, self_ty: Option, ) -> bool { + if arg.is_error() { + return true; + } + match def { SourceType::Error => true, SourceType::Any => unreachable!(), @@ -607,7 +619,9 @@ pub(super) fn arg_allows( arg_allows(sa, alias.ty(), arg, self_ty.clone()) } - SourceType::Assoc(..) | SourceType::GenericAssoc { .. } => unimplemented!(), + SourceType::GenericAssoc { .. } => def == arg, + + SourceType::Assoc(..) => unimplemented!(), } } diff --git a/dora-sema-fuzzer/src/main.rs b/dora-sema-fuzzer/src/main.rs index 482e1c001..002e64edb 100644 --- a/dora-sema-fuzzer/src/main.rs +++ b/dora-sema-fuzzer/src/main.rs @@ -16,7 +16,6 @@ fn check_program(program: String) { program_file: Some(FileContent::Content(program)), packages: Vec::new(), boots: false, - new_default_impl: true, }; let mut sa = Sema::new(sem_args); diff --git a/tests/trait/trait-default-wip.dora b/tests/trait/trait-default-wip.dora index b05d96ffa..072dcc0a9 100644 --- a/tests/trait/trait-default-wip.dora +++ b/tests/trait/trait-default-wip.dora @@ -46,7 +46,7 @@ class Map[I: MyIterator, R] { fct: (I::Item): R, } -impl[I: MyIterator] MyIterator for Map[I, R] { +impl[I: MyIterator, R] MyIterator for Map[I, R] { type Item = R; fn next(): Option[R] { @@ -81,9 +81,11 @@ fn main() { assert(Range(2).count() == 2); assert(Range(7).count() == 7); - let r = Range(2).enumerate(); + let r = Range(2).enumerate().map[Int](|x: (Int, Int)|: (Int, Int) { + (x.0, x.1 * 2) + }); - assert(Some[(Int, Int)]((0, 2)) == r.next()); - assert(Some[(Int, Int)]((1, 1)) == r.next()); + assert(Some[(Int, Int)]((0, 4)) == r.next()); + assert(Some[(Int, Int)]((1, 2)) == r.next()); assert(r.next().isNone()); }