Skip to content

Commit 3b5f0c4

Browse files
committed
Fix shadowing default method type parameters
When copying default methods to impls, rename type parameters of the methods so that they won't be shadowed by the impl's type parameters. For example, when copying this default method: trait Iterator[iter, item, exn]: map(self: iter, f: Fn(item) b / exn) Map[iter, item, b, exn]: ... to impl: impl[Iterator[iter, a, exn]] Iterator[Map[iter, a, b, exn], b, exn]: ... If we naively copy, we get: impl[Iterator[iter, a, exn]] Iterator[Map[iter, a, b, exn], b, exn]: # iter -> Map[iter, a, b, exn] # item -> b # exn -> exn map(self: Map[iter, a, b, exn], f: Fn(b) b / exn) Map[Map[iter, a, b, exn], b, b, exn]: Map(iter = self, f = f) Note that the return type of the callback argument (originally `b`) is still `b`, but `b` is now bound in impl head. To fix, we rename type parameters of copied methods by adding a `$copy` suffix. New copied method: impl[Iterator[iter, a, exn]] Iterator[Map[iter, a, b, exn], b, exn]: # iter -> Map[iter, a, b, exn] # item -> b # exn -> exn map(self: Map[iter, a, b, exn], f: Fn(b) b$copy / exn) Map[Map[iter, a, b, exn], b, b$copy, exn]: Map(iter = self, f = f) Fixes #275.
1 parent 240bcf6 commit 3b5f0c4

File tree

2 files changed

+30
-0
lines changed

2 files changed

+30
-0
lines changed

src/type_checker.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,27 @@ fn collect_cons(module: &mut ast::Module) -> TyMap {
530530

531531
let mut impl_fun_decl = trait_method_decl.fun_decl.clone();
532532

533+
// Rename copied function's type parameters so that they won't be shadowed by the impl's
534+
// type parameters.
535+
let mut new_type_params: Vec<(Id, Kind)> =
536+
Vec::with_capacity(impl_fun_decl.node.sig.context.type_params.len());
537+
538+
let renaming_substs: HashMap<Id, ast::Type> = impl_fun_decl
539+
.node
540+
.sig
541+
.context
542+
.type_params
543+
.iter()
544+
.map(|(ty_param, kind)| {
545+
let new_param = SmolStr::new(format!("{}$copy", ty_param));
546+
new_type_params.push((new_param.clone(), kind.clone()));
547+
(ty_param.clone(), ast::Type::Var(new_param))
548+
})
549+
.collect();
550+
551+
impl_fun_decl.node.sig.context.type_params = new_type_params;
552+
impl_fun_decl.node.sig.subst_ty_ids(&renaming_substs);
553+
533554
// Map type parameters of the trait to the impl types.
534555
let substs: HashMap<Id, ast::Type> = trait_type_params
535556
.iter()
@@ -539,6 +560,7 @@ fn collect_cons(module: &mut ast::Module) -> TyMap {
539560

540561
if let Some(body) = &mut impl_fun_decl.node.body {
541562
for stmt in body {
563+
stmt.node.subst_ty_ids(&renaming_substs);
542564
stmt.node.subst_ty_ids(&substs);
543565
}
544566
}

tests/Issue275.fir

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# This program was compiled to ill-typed C because of a substitution bug when
2+
# copying default trait methods.
3+
4+
main():
5+
let vec: Vec[Str] = Vec.withCapacity(1)
6+
let iter1 = vec.iter()
7+
let iter2 = iter1.map(\(s: Str): u32(1))
8+
let iter3 = iter2.map(\(n: U32): (key = n, val = ()))

0 commit comments

Comments
 (0)