]> git.lizzy.rs Git - rust.git/commitdiff
Fix another crash from wrong binders
authorFlorian Diebold <flodiebold@gmail.com>
Fri, 17 Apr 2020 20:48:29 +0000 (22:48 +0200)
committerFlorian Diebold <flodiebold@gmail.com>
Fri, 17 Apr 2020 22:01:09 +0000 (00:01 +0200)
Basically, if we had something like `dyn Trait<T>` (where `T` is a type
parameter) in an impl we lowered that to `dyn Trait<^0.0>`, when it should be
`dyn Trait<^1.0>` because the `dyn` introduces a new binder. With one type
parameter, that's just wrong, with two, it'll lead to crashes.

crates/ra_hir_ty/src/lib.rs
crates/ra_hir_ty/src/lower.rs
crates/ra_hir_ty/src/tests/traits.rs
crates/ra_hir_ty/src/traits/chalk.rs

index 2677f3af2d752e1e791513fb47ad1552e48beed7..a4b8d66837ccd10c528a6707914d438857b43445 100644 (file)
@@ -396,12 +396,12 @@ pub fn type_params(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> Substs
     }
 
     /// Return Substs that replace each parameter by a bound variable.
-    pub(crate) fn bound_vars(generic_params: &Generics) -> Substs {
+    pub(crate) fn bound_vars(generic_params: &Generics, debruijn: DebruijnIndex) -> Substs {
         Substs(
             generic_params
                 .iter()
                 .enumerate()
-                .map(|(idx, _)| Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, idx)))
+                .map(|(idx, _)| Ty::Bound(BoundVar::new(debruijn, idx)))
                 .collect(),
         )
     }
index cc1ac8e3e972b9b04a36305dc6a9b2b1d9ede2b3..c2812e1783e64422fa6221699b2f253a4debad49 100644 (file)
@@ -39,6 +39,7 @@
 pub struct TyLoweringContext<'a> {
     pub db: &'a dyn HirDatabase,
     pub resolver: &'a Resolver,
+    in_binders: DebruijnIndex,
     /// Note: Conceptually, it's thinkable that we could be in a location where
     /// some type params should be represented as placeholders, and others
     /// should be converted to variables. I think in practice, this isn't
@@ -53,7 +54,27 @@ pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver) -> Self {
         let impl_trait_counter = std::cell::Cell::new(0);
         let impl_trait_mode = ImplTraitLoweringMode::Disallowed;
         let type_param_mode = TypeParamLoweringMode::Placeholder;
-        Self { db, resolver, impl_trait_mode, impl_trait_counter, type_param_mode }
+        let in_binders = DebruijnIndex::INNERMOST;
+        Self { db, resolver, in_binders, impl_trait_mode, impl_trait_counter, type_param_mode }
+    }
+
+    pub fn with_shifted_in<T>(
+        &self,
+        debruijn: DebruijnIndex,
+        f: impl FnOnce(&TyLoweringContext) -> T,
+    ) -> T {
+        let new_ctx = Self {
+            in_binders: self.in_binders.shifted_in_from(debruijn),
+            impl_trait_counter: std::cell::Cell::new(self.impl_trait_counter.get()),
+            ..*self
+        };
+        let result = f(&new_ctx);
+        self.impl_trait_counter.set(new_ctx.impl_trait_counter.get());
+        result
+    }
+
+    pub fn shifted_in(self, debruijn: DebruijnIndex) -> Self {
+        Self { in_binders: self.in_binders.shifted_in_from(debruijn), ..self }
     }
 
     pub fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self {
@@ -134,22 +155,26 @@ pub fn from_hir_ext(ctx: &TyLoweringContext<'_>, type_ref: &TypeRef) -> (Self, O
             }
             TypeRef::DynTrait(bounds) => {
                 let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0));
-                let predicates = bounds
-                    .iter()
-                    .flat_map(|b| GenericPredicate::from_type_bound(ctx, b, self_ty.clone()))
-                    .collect();
+                let predicates = ctx.with_shifted_in(DebruijnIndex::ONE, |ctx| {
+                    bounds
+                        .iter()
+                        .flat_map(|b| GenericPredicate::from_type_bound(ctx, b, self_ty.clone()))
+                        .collect()
+                });
                 Ty::Dyn(predicates)
             }
             TypeRef::ImplTrait(bounds) => {
                 match ctx.impl_trait_mode {
                     ImplTraitLoweringMode::Opaque => {
                         let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0));
-                        let predicates = bounds
-                            .iter()
-                            .flat_map(|b| {
-                                GenericPredicate::from_type_bound(ctx, b, self_ty.clone())
-                            })
-                            .collect();
+                        let predicates = ctx.with_shifted_in(DebruijnIndex::ONE, |ctx| {
+                            bounds
+                                .iter()
+                                .flat_map(|b| {
+                                    GenericPredicate::from_type_bound(ctx, b, self_ty.clone())
+                                })
+                                .collect()
+                        });
                         Ty::Opaque(predicates)
                     }
                     ImplTraitLoweringMode::Param => {
@@ -180,7 +205,7 @@ pub fn from_hir_ext(ctx: &TyLoweringContext<'_>, type_ref: &TypeRef) -> (Self, O
                                 (0, 0, 0, 0)
                             };
                         Ty::Bound(BoundVar::new(
-                            DebruijnIndex::INNERMOST,
+                            ctx.in_binders,
                             idx as usize + parent_params + self_params + list_params,
                         ))
                     }
@@ -293,7 +318,7 @@ pub(crate) fn from_partly_resolved_hir_path(
                     TypeParamLoweringMode::Placeholder => Ty::Placeholder(param_id),
                     TypeParamLoweringMode::Variable => {
                         let idx = generics.param_idx(param_id).expect("matching generics");
-                        Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, idx))
+                        Ty::Bound(BoundVar::new(ctx.in_binders, idx))
                     }
                 }
             }
@@ -303,7 +328,9 @@ pub(crate) fn from_partly_resolved_hir_path(
                     TypeParamLoweringMode::Placeholder => {
                         Substs::type_params_for_generics(&generics)
                     }
-                    TypeParamLoweringMode::Variable => Substs::bound_vars(&generics),
+                    TypeParamLoweringMode::Variable => {
+                        Substs::bound_vars(&generics, ctx.in_binders)
+                    }
                 };
                 ctx.db.impl_self_ty(impl_id).subst(&substs)
             }
@@ -313,7 +340,9 @@ pub(crate) fn from_partly_resolved_hir_path(
                     TypeParamLoweringMode::Placeholder => {
                         Substs::type_params_for_generics(&generics)
                     }
-                    TypeParamLoweringMode::Variable => Substs::bound_vars(&generics),
+                    TypeParamLoweringMode::Variable => {
+                        Substs::bound_vars(&generics, ctx.in_binders)
+                    }
                 };
                 ctx.db.ty(adt.into()).subst(&substs)
             }
@@ -797,7 +826,7 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
 /// function body.
 fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> Binders<Ty> {
     let generics = generics(db.upcast(), def.into());
-    let substs = Substs::bound_vars(&generics);
+    let substs = Substs::bound_vars(&generics, DebruijnIndex::INNERMOST);
     Binders::new(substs.len(), Ty::apply(TypeCtor::FnDef(def.into()), substs))
 }
 
@@ -851,7 +880,7 @@ fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Binders<T
         return type_for_adt(db, def.into());
     }
     let generics = generics(db.upcast(), def.into());
-    let substs = Substs::bound_vars(&generics);
+    let substs = Substs::bound_vars(&generics, DebruijnIndex::INNERMOST);
     Binders::new(substs.len(), Ty::apply(TypeCtor::FnDef(def.into()), substs))
 }
 
@@ -876,13 +905,13 @@ fn type_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -
         return type_for_adt(db, def.parent.into());
     }
     let generics = generics(db.upcast(), def.parent.into());
-    let substs = Substs::bound_vars(&generics);
+    let substs = Substs::bound_vars(&generics, DebruijnIndex::INNERMOST);
     Binders::new(substs.len(), Ty::apply(TypeCtor::FnDef(def.into()), substs))
 }
 
 fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
     let generics = generics(db.upcast(), adt.into());
-    let substs = Substs::bound_vars(&generics);
+    let substs = Substs::bound_vars(&generics, DebruijnIndex::INNERMOST);
     Binders::new(substs.len(), Ty::apply(TypeCtor::Adt(adt), substs))
 }
 
@@ -892,7 +921,7 @@ fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
     let ctx =
         TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
     let type_ref = &db.type_alias_data(t).type_ref;
-    let substs = Substs::bound_vars(&generics);
+    let substs = Substs::bound_vars(&generics, DebruijnIndex::INNERMOST);
     let inner = Ty::from_hir(&ctx, type_ref.as_ref().unwrap_or(&TypeRef::Error));
     Binders::new(substs.len(), inner)
 }
index 0a889f8057e60eeebed77041d6c89cef394f0109..36f53b264d013cb0dad29bb5d561fa3d1f31aeee 100644 (file)
@@ -1210,6 +1210,42 @@ fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) {
     );
 }
 
+#[test]
+fn dyn_trait_in_impl() {
+    assert_snapshot!(
+        infer(r#"
+trait Trait<T, U> {
+    fn foo(&self) -> (T, U);
+}
+struct S<T, U> {}
+impl<T, U> S<T, U> {
+    fn bar(&self) -> &dyn Trait<T, U> { loop {} }
+}
+trait Trait2<T, U> {
+    fn baz(&self) -> (T, U);
+}
+impl<T, U> Trait2<T, U> for dyn Trait<T, U> { }
+
+fn test(s: S<u32, i32>) {
+    s.bar().baz();
+}
+"#),
+        @r###"
+    [33; 37) 'self': &Self
+    [103; 107) 'self': &S<T, U>
+    [129; 140) '{ loop {} }': &dyn Trait<T, U>
+    [131; 138) 'loop {}': !
+    [136; 138) '{}': ()
+    [176; 180) 'self': &Self
+    [252; 253) 's': S<u32, i32>
+    [268; 290) '{     ...z(); }': ()
+    [274; 275) 's': S<u32, i32>
+    [274; 281) 's.bar()': &dyn Trait<u32, i32>
+    [274; 287) 's.bar().baz()': (u32, i32)
+    "###
+    );
+}
+
 #[test]
 fn dyn_trait_bare() {
     assert_snapshot!(
index 60d70d18e89d031612e196e4fc177ef66587daa8..e00a82db2a895feefb934b60546b31f0778db2fa 100644 (file)
@@ -17,7 +17,7 @@
 use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation};
 use crate::{
     db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics,
-    ApplicationTy, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
+    ApplicationTy, DebruijnIndex, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
 };
 
 pub(super) mod tls;
@@ -815,7 +815,7 @@ pub(crate) fn associated_ty_data_query(
     // Lower bounds -- we could/should maybe move this to a separate query in `lower`
     let type_alias_data = db.type_alias_data(type_alias);
     let generic_params = generics(db.upcast(), type_alias.into());
-    let bound_vars = Substs::bound_vars(&generic_params);
+    let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
     let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
     let ctx = crate::TyLoweringContext::new(db, &resolver)
         .with_type_param_mode(crate::lower::TypeParamLoweringMode::Variable);
@@ -849,7 +849,7 @@ pub(crate) fn trait_datum_query(
     let trait_data = db.trait_data(trait_);
     debug!("trait {:?} = {:?}", trait_id, trait_data.name);
     let generic_params = generics(db.upcast(), trait_.into());
-    let bound_vars = Substs::bound_vars(&generic_params);
+    let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
     let flags = chalk_rust_ir::TraitFlags {
         auto: trait_data.auto,
         upstream: trait_.lookup(db.upcast()).container.module(db.upcast()).krate != krate,
@@ -888,7 +888,7 @@ pub(crate) fn struct_datum_query(
         .as_generic_def()
         .map(|generic_def| {
             let generic_params = generics(db.upcast(), generic_def);
-            let bound_vars = Substs::bound_vars(&generic_params);
+            let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
             convert_where_clauses(db, generic_def, &bound_vars)
         })
         .unwrap_or_else(Vec::new);
@@ -934,7 +934,7 @@ fn impl_def_datum(
     let impl_data = db.impl_data(impl_id);
 
     let generic_params = generics(db.upcast(), impl_id.into());
-    let bound_vars = Substs::bound_vars(&generic_params);
+    let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
     let trait_ = trait_ref.trait_;
     let impl_type = if impl_id.lookup(db.upcast()).container.module(db.upcast()).krate == krate {
         chalk_rust_ir::ImplType::Local