]> git.lizzy.rs Git - rust.git/commitdiff
Adapt to the new generic parameter/argument order
authorRyo Yoshida <low.ryoshida@gmail.com>
Sun, 2 Oct 2022 13:15:57 +0000 (22:15 +0900)
committerRyo Yoshida <low.ryoshida@gmail.com>
Sun, 2 Oct 2022 17:40:07 +0000 (02:40 +0900)
crates/hir-ty/src/autoderef.rs
crates/hir-ty/src/chalk_db.rs
crates/hir-ty/src/display.rs
crates/hir-ty/src/infer.rs
crates/hir-ty/src/infer/expr.rs
crates/hir-ty/src/infer/path.rs
crates/hir-ty/src/infer/unify.rs
crates/hir-ty/src/lower.rs
crates/hir-ty/src/method_resolution.rs
crates/hir/src/lib.rs
crates/hir/src/source_analyzer.rs

index 344036dd8139d28d433c745b6121ab8c85e9865f..02332ea80d883f1ed9a036750a2305387ca464b5 100644 (file)
@@ -123,13 +123,14 @@ fn deref_by_trait(table: &mut InferenceTable<'_>, ty: Ty) -> Option<Ty> {
     let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?;
 
     let projection = {
-        let b = TyBuilder::assoc_type_projection(db, target);
+        let b = TyBuilder::subst_for_def(db, deref_trait, None);
         if b.remaining() != 1 {
             // the Target type + Deref trait should only have one generic parameter,
             // namely Deref's Self type
             return None;
         }
-        b.push(ty).build()
+        let deref_subst = b.push(ty).build();
+        TyBuilder::assoc_type_projection(db, target, Some(deref_subst)).build()
     };
 
     // Check that the type implements Deref at all
index c5cf6729d119991ff1d95fef4062be613339354e..3f3f8f7d0f2a2ac9d82b02fdb0439dd978713f0c 100644 (file)
@@ -382,13 +382,12 @@ fn generator_datum(
         // `resume_type`, `yield_type`, and `return_type` of the generator in question.
         let subst = TyBuilder::subst_for_generator(self.db, parent).fill_with_unknown().build();
 
-        let len = subst.len(Interner);
         let input_output = rust_ir::GeneratorInputOutputDatum {
-            resume_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, len - 3))
+            resume_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
                 .intern(Interner),
-            yield_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, len - 2))
+            yield_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 1))
                 .intern(Interner),
-            return_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, len - 1))
+            return_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 2))
                 .intern(Interner),
             // FIXME: calculate upvars
             upvars: vec![],
@@ -476,10 +475,15 @@ pub(crate) fn associated_ty_data_query(
     let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
     let ctx = crate::TyLoweringContext::new(db, &resolver)
         .with_type_param_mode(crate::lower::ParamLoweringMode::Variable);
-    let pro_ty = TyBuilder::assoc_type_projection(db, type_alias)
+
+    let trait_subst = TyBuilder::subst_for_def(db, trait_, None)
+        .fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, generic_params.len_self())
+        .build();
+    let pro_ty = TyBuilder::assoc_type_projection(db, type_alias, Some(trait_subst))
         .fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, 0)
         .build();
     let self_ty = TyKind::Alias(AliasTy::Projection(pro_ty)).intern(Interner);
+
     let mut bounds: Vec<_> = type_alias_data
         .bounds
         .iter()
index a5058f71a4a6d030fd9d40e7650d50eb26583d49..7f0baf49dadce9e510a0b133d811b2fde49ff19c 100644 (file)
@@ -27,7 +27,7 @@
     db::HirDatabase,
     from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, lt_from_placeholder_idx,
     mapping::from_chalk,
-    primitive, subst_prefix, to_assoc_type_id,
+    primitive, to_assoc_type_id,
     utils::{self, generics},
     AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Const, ConstValue, DomainGoal,
     GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives, Mutability,
@@ -506,8 +506,15 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
                     let total_len = parent_params + self_param + type_params + const_params;
                     // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
                     if total_len > 0 {
+                        // `parameters` are in the order of fn's params (including impl traits),
+                        // parent's params (those from enclosing impl or trait, if any).
+                        let parameters = parameters.as_slice(Interner);
+                        let fn_params_len = self_param + type_params + const_params;
+                        let fn_params = parameters.get(..fn_params_len);
+                        let parent_params = parameters.get(parameters.len() - parent_params..);
+                        let params = parent_params.into_iter().chain(fn_params).flatten();
                         write!(f, "<")?;
-                        f.write_joined(&parameters.as_slice(Interner)[..total_len], ", ")?;
+                        f.write_joined(params, ", ")?;
                         write!(f, ">")?;
                     }
                 }
@@ -579,9 +586,8 @@ fn should_show(
                                         Some(x) => x,
                                         None => return true,
                                     };
-                                    let actual_default = default_parameter
-                                        .clone()
-                                        .substitute(Interner, &subst_prefix(parameters, i));
+                                    let actual_default =
+                                        default_parameter.clone().substitute(Interner, &parameters);
                                     parameter != &actual_default
                                 }
                                 let mut default_from = 0;
index 25179afaca7ade63893f317c6bbd3a92033121d9..31e56dec62593770bb938e2ddaa7dc7f6b39731c 100644 (file)
@@ -26,8 +26,8 @@
     path::{path, Path},
     resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
     type_ref::TypeRef,
-    AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule, Lookup,
-    TraitId, TypeAliasId, VariantId,
+    AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule,
+    ItemContainerId, Lookup, TraitId, TypeAliasId, VariantId,
 };
 use hir_expand::name::{name, Name};
 use itertools::Either;
@@ -713,6 +713,8 @@ fn resolve_associated_type_with_params(
         &mut self,
         inner_ty: Ty,
         assoc_ty: Option<TypeAliasId>,
+        // FIXME(GATs): these are args for the trait ref, args for assoc type itself should be
+        // handled when we support them.
         params: &[GenericArg],
     ) -> Ty {
         match assoc_ty {
@@ -804,7 +806,18 @@ fn resolve_variant(&mut self, path: Option<&Path>, value_ns: bool) -> (Ty, Optio
                 self.resolve_variant_on_alias(ty, unresolved, path)
             }
             TypeNs::TypeAliasId(it) => {
-                let ty = TyBuilder::def_ty(self.db, it.into())
+                let container = it.lookup(self.db.upcast()).container;
+                let parent_subst = match container {
+                    ItemContainerId::TraitId(id) => {
+                        let subst = TyBuilder::subst_for_def(self.db, id, None)
+                            .fill_with_inference_vars(&mut self.table)
+                            .build();
+                        Some(subst)
+                    }
+                    // Type aliases do not exist in impls.
+                    _ => None,
+                };
+                let ty = TyBuilder::def_ty(self.db, it.into(), parent_subst)
                     .fill_with_inference_vars(&mut self.table)
                     .build();
                 self.resolve_variant_on_alias(ty, unresolved, path)
index 2643baf8a32996680b0efd0c62e1ed8ca18992fb..f56108b26c45bdaea3096f4616828c28ba260d12 100644 (file)
@@ -987,11 +987,13 @@ fn infer_overloadable_binop(
         let lhs_ty = self.infer_expr(lhs, &lhs_expectation);
         let rhs_ty = self.table.new_type_var();
 
-        let func = lang_names_for_bin_op(op).and_then(|(name, lang_item)| {
-            self.db.trait_data(self.resolve_lang_item(lang_item)?.as_trait()?).method_by_name(&name)
+        let trait_func = lang_names_for_bin_op(op).and_then(|(name, lang_item)| {
+            let trait_id = self.resolve_lang_item(lang_item)?.as_trait()?;
+            let func = self.db.trait_data(trait_id).method_by_name(&name)?;
+            Some((trait_id, func))
         });
-        let func = match func {
-            Some(func) => func,
+        let (trait_, func) = match trait_func {
+            Some(it) => it,
             None => {
                 let rhs_ty = self.builtin_binary_op_rhs_expectation(op, lhs_ty.clone());
                 let rhs_ty = self.infer_expr_coerce(rhs, &Expectation::from_option(rhs_ty));
@@ -1001,7 +1003,9 @@ fn infer_overloadable_binop(
             }
         };
 
-        let subst = TyBuilder::subst_for_def(self.db, func)
+        // HACK: We can use this substitution for the function because the function itself doesn't
+        // have its own generic parameters.
+        let subst = TyBuilder::subst_for_def(self.db, trait_, None)
             .push(lhs_ty.clone())
             .push(rhs_ty.clone())
             .build();
@@ -1280,19 +1284,7 @@ fn substs_for_method_call(
         assert_eq!(self_params, 0); // method shouldn't have another Self param
         let total_len = parent_params + type_params + const_params + impl_trait_params;
         let mut substs = Vec::with_capacity(total_len);
-        // Parent arguments are unknown
-        for (id, param) in def_generics.iter_parent() {
-            match param {
-                TypeOrConstParamData::TypeParamData(_) => {
-                    substs.push(GenericArgData::Ty(self.table.new_type_var()).intern(Interner));
-                }
-                TypeOrConstParamData::ConstParamData(_) => {
-                    let ty = self.db.const_param_ty(ConstParamId::from_unchecked(id));
-                    substs
-                        .push(GenericArgData::Const(self.table.new_const_var(ty)).intern(Interner));
-                }
-            }
-        }
+
         // handle provided arguments
         if let Some(generic_args) = generic_args {
             // if args are provided, it should be all of them, but we can't rely on that
@@ -1301,7 +1293,7 @@ fn substs_for_method_call(
                 .iter()
                 .filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
                 .take(type_params + const_params)
-                .zip(def_generics.iter_id().skip(parent_params))
+                .zip(def_generics.iter_id())
             {
                 if let Some(g) = generic_arg_to_chalk(
                     self.db,
@@ -1325,6 +1317,9 @@ fn substs_for_method_call(
                 }
             }
         };
+
+        // Handle everything else as unknown. This also handles generic arguments for the method's
+        // parent (impl or trait), which should come after those for the method.
         for (id, data) in def_generics.iter().skip(substs.len()) {
             match data {
                 TypeOrConstParamData::TypeParamData(_) => {
@@ -1362,9 +1357,13 @@ fn register_obligations_for_call(&mut self, callable_ty: &Ty) {
                 CallableDefId::FunctionId(f) => {
                     if let ItemContainerId::TraitId(trait_) = f.lookup(self.db.upcast()).container {
                         // construct a TraitRef
-                        let substs = crate::subst_prefix(
-                            &*parameters,
-                            generics(self.db.upcast(), trait_.into()).len(),
+                        let params_len = parameters.len(Interner);
+                        let trait_params_len = generics(self.db.upcast(), trait_.into()).len();
+                        let substs = Substitution::from_iter(
+                            Interner,
+                            // The generic parameters for the trait come after those for the
+                            // function.
+                            &parameters.as_slice(Interner)[params_len - trait_params_len..],
                         );
                         self.push_obligation(
                             TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs }
index 7bb79b519e1caf3dbd9b757d5dba6d7540c9970e..7a4754cdc7bb899848ea9b032825945407e13850 100644 (file)
@@ -12,6 +12,7 @@
     builder::ParamKind,
     consteval,
     method_resolution::{self, VisibleFromModule},
+    utils::generics,
     Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, ValueTyDefId,
 };
 
@@ -95,12 +96,18 @@ fn resolve_value_path(
             ValueNs::GenericParam(it) => return Some(self.db.const_param_ty(it)),
         };
 
-        let parent_substs = self_subst.unwrap_or_else(|| Substitution::empty(Interner));
         let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
         let substs = ctx.substs_from_path(path, typable, true);
-        let mut it = substs.as_slice(Interner)[parent_substs.len(Interner)..].iter().cloned();
-        let ty = TyBuilder::value_ty(self.db, typable)
-            .use_parent_substs(&parent_substs)
+        let substs = substs.as_slice(Interner);
+        let parent_substs = self_subst.or_else(|| {
+            let generics = generics(self.db.upcast(), typable.to_generic_def_id()?);
+            let parent_params_len = generics.parent_generics()?.len();
+            let parent_args = &substs[substs.len() - parent_params_len..];
+            Some(Substitution::from_iter(Interner, parent_args))
+        });
+        let parent_substs_len = parent_substs.as_ref().map_or(0, |s| s.len(Interner));
+        let mut it = substs.iter().take(substs.len() - parent_substs_len).cloned();
+        let ty = TyBuilder::value_ty(self.db, typable, parent_substs)
             .fill(|x| {
                 it.next().unwrap_or_else(|| match x {
                     ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
@@ -246,7 +253,7 @@ fn resolve_ty_assoc_item(
                 };
                 let substs = match container {
                     ItemContainerId::ImplId(impl_id) => {
-                        let impl_substs = TyBuilder::subst_for_def(self.db, impl_id)
+                        let impl_substs = TyBuilder::subst_for_def(self.db, impl_id, None)
                             .fill_with_inference_vars(&mut self.table)
                             .build();
                         let impl_self_ty =
index e77b55670b5e1b6c3881129d3497e82d06c39c37..6ccd0b215c6e480e72e17ed62a663ffc2d02ad9c 100644 (file)
@@ -598,11 +598,14 @@ fn callable_sig_from_fn_trait(&mut self, ty: &Ty, num_args: usize) -> Option<(Ve
             .build();
 
         let projection = {
-            let b = TyBuilder::assoc_type_projection(self.db, output_assoc_type);
+            let b = TyBuilder::subst_for_def(self.db, fn_once_trait, None);
             if b.remaining() != 2 {
                 return None;
             }
-            b.push(ty.clone()).push(arg_ty).build()
+            let fn_once_subst = b.push(ty.clone()).push(arg_ty).build();
+
+            TyBuilder::assoc_type_projection(self.db, output_assoc_type, Some(fn_once_subst))
+                .build()
         };
 
         let trait_env = self.trait_env.env.clone();
index 82128ae6586d161a173b3a9fc512b8e21c9309b0..0a4b1dfda105555888fbcc9248101e241d379236 100644 (file)
@@ -306,7 +306,7 @@ pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
                         // FIXME we're probably doing something wrong here
                         self.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16);
                         let (
-                            parent_params,
+                            _parent_params,
                             self_params,
                             list_params,
                             const_params,
@@ -319,7 +319,7 @@ pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
                         };
                         TyKind::BoundVar(BoundVar::new(
                             self.in_binders,
-                            idx as usize + parent_params + self_params + list_params + const_params,
+                            idx as usize + self_params + list_params + const_params,
                         ))
                         .intern(Interner)
                     }
@@ -499,14 +499,31 @@ pub(crate) fn lower_partly_resolved_path(
                 .intern(Interner)
             }
             TypeNs::SelfType(impl_id) => {
-                let generics = generics(self.db.upcast(), impl_id.into());
-                let substs = match self.type_param_mode {
-                    ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db),
+                let def =
+                    self.resolver.generic_def().expect("impl should have generic param scope");
+                let generics = generics(self.db.upcast(), def);
+
+                match self.type_param_mode {
+                    ParamLoweringMode::Placeholder => {
+                        // `def` can be either impl itself or item within, and we need impl itself
+                        // now.
+                        let generics = generics.parent_generics().unwrap_or(&generics);
+                        let subst = generics.placeholder_subst(self.db);
+                        self.db.impl_self_ty(impl_id).substitute(Interner, &subst)
+                    }
                     ParamLoweringMode::Variable => {
-                        generics.bound_vars_subst(self.db, self.in_binders)
+                        let starting_from = match def {
+                            GenericDefId::ImplId(_) => 0,
+                            // `def` is an item within impl. We need to substitute `BoundVar`s but
+                            // remember that they are for parent (i.e. impl) generic params so they
+                            // come after our own params.
+                            _ => generics.len_self(),
+                        };
+                        TyBuilder::impl_self_ty(self.db, impl_id)
+                            .fill_with_bound_vars(self.in_binders, starting_from)
+                            .build()
                     }
-                };
-                self.db.impl_self_ty(impl_id).substitute(Interner, &substs)
+                }
             }
             TypeNs::AdtSelfType(adt) => {
                 let generics = generics(self.db.upcast(), adt.into());
@@ -636,13 +653,9 @@ pub(super) fn substs_from_path(
         infer_args: bool,
     ) -> Substitution {
         let last = path.segments().last().expect("path should have at least one segment");
-        let (segment, generic_def) = match resolved {
-            ValueTyDefId::FunctionId(it) => (last, Some(it.into())),
-            ValueTyDefId::StructId(it) => (last, Some(it.into())),
-            ValueTyDefId::UnionId(it) => (last, Some(it.into())),
-            ValueTyDefId::ConstId(it) => (last, Some(it.into())),
-            ValueTyDefId::StaticId(_) => (last, None),
-            ValueTyDefId::EnumVariantId(var) => {
+        let generic_def = resolved.to_generic_def_id();
+        let segment = match resolved {
+            ValueTyDefId::EnumVariantId(_) => {
                 // the generic args for an enum variant may be either specified
                 // on the segment referring to the enum, or on the segment
                 // referring to the variant. So `Option::<T>::None` and
@@ -650,12 +663,12 @@ pub(super) fn substs_from_path(
                 // preferred). See also `def_ids_for_path_segments` in rustc.
                 let len = path.segments().len();
                 let penultimate = len.checked_sub(2).and_then(|idx| path.segments().get(idx));
-                let segment = match penultimate {
+                match penultimate {
                     Some(segment) if segment.args_and_bindings.is_some() => segment,
                     _ => last,
-                };
-                (segment, Some(var.parent.into()))
+                }
             }
+            _ => last,
         };
         self.substs_from_path_segment(segment, generic_def, infer_args, None)
     }
@@ -663,36 +676,27 @@ pub(super) fn substs_from_path(
     fn substs_from_path_segment(
         &self,
         segment: PathSegment<'_>,
-        def_generic: Option<GenericDefId>,
+        def: Option<GenericDefId>,
         infer_args: bool,
         explicit_self_ty: Option<Ty>,
     ) -> Substitution {
+        // Remember that the item's own generic args come before its parent's.
         let mut substs = Vec::new();
-        let def_generics = if let Some(def) = def_generic {
-            generics(self.db.upcast(), def)
+        let def = if let Some(d) = def {
+            d
         } else {
             return Substitution::empty(Interner);
         };
+        let def_generics = generics(self.db.upcast(), def);
         let (parent_params, self_params, type_params, const_params, impl_trait_params) =
             def_generics.provenance_split();
-        let total_len =
-            parent_params + self_params + type_params + const_params + impl_trait_params;
+        let item_len = self_params + type_params + const_params + impl_trait_params;
+        let total_len = parent_params + item_len;
 
         let ty_error = TyKind::Error.intern(Interner).cast(Interner);
 
         let mut def_generic_iter = def_generics.iter_id();
 
-        for _ in 0..parent_params {
-            if let Some(eid) = def_generic_iter.next() {
-                match eid {
-                    Either::Left(_) => substs.push(ty_error.clone()),
-                    Either::Right(x) => {
-                        substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
-                    }
-                }
-            }
-        }
-
         let fill_self_params = || {
             for x in explicit_self_ty
                 .into_iter()
@@ -757,37 +761,40 @@ fn substs_from_path_segment(
             fill_self_params();
         }
 
+        // These params include those of parent.
+        let remaining_params: SmallVec<[_; 2]> = def_generic_iter
+            .map(|eid| match eid {
+                Either::Left(_) => ty_error.clone(),
+                Either::Right(x) => unknown_const_as_generic(self.db.const_param_ty(x)),
+            })
+            .collect();
+        assert_eq!(remaining_params.len() + substs.len(), total_len);
+
         // handle defaults. In expression or pattern path segments without
         // explicitly specified type arguments, missing type arguments are inferred
         // (i.e. defaults aren't used).
         if !infer_args || had_explicit_args {
-            if let Some(def_generic) = def_generic {
-                let defaults = self.db.generic_defaults(def_generic);
-                assert_eq!(total_len, defaults.len());
-
-                for default_ty in defaults.iter().skip(substs.len()) {
-                    // each default can depend on the previous parameters
-                    let substs_so_far = Substitution::from_iter(Interner, substs.clone());
-                    if let Some(_id) = def_generic_iter.next() {
-                        substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
-                    }
-                }
+            let defaults = self.db.generic_defaults(def);
+            assert_eq!(total_len, defaults.len());
+            let parent_from = item_len - substs.len();
+
+            for (idx, default_ty) in defaults[substs.len()..item_len].iter().enumerate() {
+                // each default can depend on the previous parameters
+                let substs_so_far = Substitution::from_iter(
+                    Interner,
+                    substs.iter().cloned().chain(remaining_params[idx..].iter().cloned()),
+                );
+                substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
             }
-        }
 
-        // add placeholders for args that were not provided
-        // FIXME: emit diagnostics in contexts where this is not allowed
-        for eid in def_generic_iter {
-            match eid {
-                Either::Left(_) => substs.push(ty_error.clone()),
-                Either::Right(x) => {
-                    substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
-                }
-            }
+            // Keep parent's params as unknown.
+            let mut remaining_params = remaining_params;
+            substs.extend(remaining_params.drain(parent_from..));
+        } else {
+            substs.extend(remaining_params);
         }
-        // If this assert fails, it means you pushed into subst but didn't call .next() of def_generic_iter
-        assert_eq!(substs.len(), total_len);
 
+        assert_eq!(substs.len(), total_len);
         Substitution::from_iter(Interner, substs)
     }
 
@@ -1168,10 +1175,18 @@ fn named_associated_type_shorthand_candidates<R>(
             }
             // Handle `Self::Type` referring to own associated type in trait definitions
             if let GenericDefId::TraitId(trait_id) = param_id.parent() {
-                let generics = generics(db.upcast(), trait_id.into());
-                if generics.params.type_or_consts[param_id.local_id()].is_trait_self() {
+                let trait_generics = generics(db.upcast(), trait_id.into());
+                if trait_generics.params.type_or_consts[param_id.local_id()].is_trait_self() {
+                    let def_generics = generics(db.upcast(), def);
+                    let starting_idx = match def {
+                        GenericDefId::TraitId(_) => 0,
+                        // `def` is an item within trait. We need to substitute `BoundVar`s but
+                        // remember that they are for parent (i.e. trait) generic params so they
+                        // come after our own params.
+                        _ => def_generics.len_self(),
+                    };
                     let trait_ref = TyBuilder::trait_ref(db, trait_id)
-                        .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
+                        .fill_with_bound_vars(DebruijnIndex::INNERMOST, starting_idx)
                         .build();
                     return search(trait_ref);
                 }
@@ -1413,6 +1428,7 @@ pub(crate) fn generic_defaults_query(
     let ctx =
         TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
     let generic_params = generics(db.upcast(), def);
+    let parent_start_idx = generic_params.len_self();
 
     let defaults = generic_params
         .iter()
@@ -1425,19 +1441,17 @@ pub(crate) fn generic_defaults_query(
                     let val = unknown_const_as_generic(
                         db.const_param_ty(ConstParamId::from_unchecked(id)),
                     );
-                    return crate::make_binders_with_count(db, idx, &generic_params, val);
+                    return make_binders(db, &generic_params, val);
                 }
             };
             let mut ty =
                 p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t));
 
             // Each default can only refer to previous parameters.
-            // type variable default referring to parameter coming
-            // after it. This is forbidden (FIXME: report
-            // diagnostic)
-            ty = fallback_bound_vars(ty, idx);
-            let val = GenericArgData::Ty(ty).intern(Interner);
-            crate::make_binders_with_count(db, idx, &generic_params, val)
+            // Type variable default referring to parameter coming
+            // after it is forbidden (FIXME: report diagnostic)
+            ty = fallback_bound_vars(ty, idx, parent_start_idx);
+            crate::make_binders(db, &generic_params, ty.cast(Interner))
         })
         .collect();
 
@@ -1454,15 +1468,14 @@ pub(crate) fn generic_defaults_recover(
     // we still need one default per parameter
     let defaults = generic_params
         .iter_id()
-        .enumerate()
-        .map(|(count, id)| {
+        .map(|id| {
             let val = match id {
                 itertools::Either::Left(_) => {
                     GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
                 }
                 itertools::Either::Right(id) => unknown_const_as_generic(db.const_param_ty(id)),
             };
-            crate::make_binders_with_count(db, count, &generic_params, val)
+            crate::make_binders(db, &generic_params, val)
         })
         .collect();
 
@@ -1837,26 +1850,48 @@ pub(crate) fn const_or_path_to_chalk(
     }
 }
 
-/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
-/// num_vars_to_keep) by `TyKind::Unknown`.
+/// Replaces any 'free' `BoundVar`s in `s` by `TyKind::Error` from the perspective of generic
+/// parameter whose index is `param_index`. A `BoundVar` is free when it is or (syntactically)
+/// appears after the generic parameter of `param_index`.
 fn fallback_bound_vars<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>(
     s: T,
-    num_vars_to_keep: usize,
+    param_index: usize,
+    parent_start: usize,
 ) -> T {
+    // Keep in mind that parent generic parameters, if any, come *after* those of the item in
+    // question. In the diagrams below, `c*` and `p*` represent generic parameters of the item and
+    // its parent respectively.
+    let is_allowed = |index| {
+        if param_index < parent_start {
+            // The parameter of `param_index` is one from the item in question. Any parent generic
+            // parameters or the item's generic parameters that come before `param_index` is
+            // allowed.
+            // [c1, .., cj, .., ck, p1, .., pl] where cj is `param_index`
+            //  ^^^^^^              ^^^^^^^^^^ these are allowed
+            !(param_index..parent_start).contains(&index)
+        } else {
+            // The parameter of `param_index` is one from the parent generics. Only parent generic
+            // parameters that come before `param_index` are allowed.
+            // [c1, .., ck, p1, .., pj, .., pl] where pj is `param_index`
+            //              ^^^^^^ these are allowed
+            (parent_start..param_index).contains(&index)
+        }
+    };
+
     crate::fold_free_vars(
         s,
         |bound, binders| {
-            if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
-                TyKind::Error.intern(Interner)
-            } else {
+            if bound.index_if_innermost().map_or(true, is_allowed) {
                 bound.shifted_in_from(binders).to_ty(Interner)
+            } else {
+                TyKind::Error.intern(Interner)
             }
         },
         |ty, bound, binders| {
-            if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
-                unknown_const(ty.clone())
-            } else {
+            if bound.index_if_innermost().map_or(true, is_allowed) {
                 bound.shifted_in_from(binders).to_const(Interner, ty)
+            } else {
+                unknown_const(ty.clone())
             }
         },
     )
index 41fcef73d9be40827aa671979c8da0f0931560c6..5998680dcd395390dcee0197baf6c8b6052a8acb 100644 (file)
@@ -654,7 +654,7 @@ fn find_matching_impl(
         let r = table.run_in_snapshot(|table| {
             let impl_data = db.impl_data(impl_);
             let substs =
-                TyBuilder::subst_for_def(db, impl_).fill_with_inference_vars(table).build();
+                TyBuilder::subst_for_def(db, impl_, None).fill_with_inference_vars(table).build();
             let impl_ty = db.impl_self_ty(impl_).substitute(Interner, &substs);
 
             table
@@ -1147,10 +1147,9 @@ fn is_valid_candidate(
             }));
             if let ItemContainerId::ImplId(impl_id) = c.lookup(db.upcast()).container {
                 let self_ty_matches = table.run_in_snapshot(|table| {
-                    let subst =
-                        TyBuilder::subst_for_def(db, c).fill_with_inference_vars(table).build();
-                    let expected_self_ty =
-                        subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner);
+                    let expected_self_ty = TyBuilder::impl_self_ty(db, impl_id)
+                        .fill_with_inference_vars(table)
+                        .build();
                     table.unify(&expected_self_ty, &self_ty)
                 });
                 if !self_ty_matches {
@@ -1186,31 +1185,26 @@ fn is_valid_fn_candidate(
 
     table.run_in_snapshot(|table| {
         let container = fn_id.lookup(db.upcast()).container;
-        let impl_subst = match container {
+        let (impl_subst, expect_self_ty) = match container {
             ItemContainerId::ImplId(it) => {
-                TyBuilder::subst_for_def(db, it).fill_with_inference_vars(table).build()
+                let subst =
+                    TyBuilder::subst_for_def(db, it, None).fill_with_inference_vars(table).build();
+                let self_ty = db.impl_self_ty(it).substitute(Interner, &subst);
+                (subst, self_ty)
             }
             ItemContainerId::TraitId(it) => {
-                TyBuilder::subst_for_def(db, it).fill_with_inference_vars(table).build()
+                let subst =
+                    TyBuilder::subst_for_def(db, it, None).fill_with_inference_vars(table).build();
+                let self_ty = subst.at(Interner, 0).assert_ty_ref(Interner).clone();
+                (subst, self_ty)
             }
             _ => unreachable!(),
         };
 
-        let fn_subst = TyBuilder::subst_for_def(db, fn_id)
-            .use_parent_substs(&impl_subst)
+        let fn_subst = TyBuilder::subst_for_def(db, fn_id, Some(impl_subst.clone()))
             .fill_with_inference_vars(table)
             .build();
 
-        let expect_self_ty = match container {
-            ItemContainerId::TraitId(_) => fn_subst.at(Interner, 0).assert_ty_ref(Interner).clone(),
-            ItemContainerId::ImplId(impl_id) => {
-                fn_subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner)
-            }
-            // We should only get called for associated items (impl/trait)
-            ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
-                unreachable!()
-            }
-        };
         check_that!(table.unify(&expect_self_ty, self_ty));
 
         if let Some(receiver_ty) = receiver_ty {
index d1c8fa59aef473b850f52bfd4993932514d75fcb..e08dd8dadebc5759dd38fc4ae061933712caf718 100644 (file)
@@ -61,7 +61,6 @@
     diagnostics::BodyValidationDiagnostic,
     method_resolution::{self, TyFingerprint},
     primitive::UintTy,
-    subst_prefix,
     traits::FnTrait,
     AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId,
     GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
@@ -1090,7 +1089,7 @@ pub fn ty(self, db: &dyn HirDatabase) -> Type {
     pub fn ty_with_args(self, db: &dyn HirDatabase, args: &[Type]) -> Type {
         let id = AdtId::from(self);
         let mut it = args.iter().map(|t| t.ty.clone());
-        let ty = TyBuilder::def_ty(db, id.into())
+        let ty = TyBuilder::def_ty(db, id.into(), None)
             .fill(|x| {
                 let r = it.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
                 match x {
@@ -2547,7 +2546,7 @@ pub fn default(self, db: &dyn HirDatabase) -> Option<Type> {
         let resolver = self.id.parent().resolver(db.upcast());
         let ty = params.get(local_idx)?.clone();
         let subst = TyBuilder::placeholder_subst(db, self.id.parent());
-        let ty = ty.substitute(Interner, &subst_prefix(&subst, local_idx));
+        let ty = ty.substitute(Interner, &subst);
         match ty.data(Interner) {
             GenericArgData::Ty(x) => Some(Type::new_with_resolver_inner(db, &resolver, x.clone())),
             _ => None,
@@ -2801,7 +2800,18 @@ fn new(db: &dyn HirDatabase, lexical_env: impl HasResolver, ty: Ty) -> Type {
     }
 
     fn from_def(db: &dyn HirDatabase, def: impl HasResolver + Into<TyDefId>) -> Type {
-        let ty = TyBuilder::def_ty(db, def.into()).fill_with_unknown().build();
+        let ty_def = def.into();
+        let parent_subst = match ty_def {
+            TyDefId::TypeAliasId(id) => match id.lookup(db.upcast()).container {
+                ItemContainerId::TraitId(id) => {
+                    let subst = TyBuilder::subst_for_def(db, id, None).fill_with_unknown().build();
+                    Some(subst)
+                }
+                _ => None,
+            },
+            _ => None,
+        };
+        let ty = TyBuilder::def_ty(db, ty_def, parent_subst).fill_with_unknown().build();
         Type::new(db, def, ty)
     }
 
@@ -2941,7 +2951,11 @@ pub fn normalize_trait_assoc_type(
         alias: TypeAlias,
     ) -> Option<Type> {
         let mut args = args.iter();
-        let projection = TyBuilder::assoc_type_projection(db, alias.id)
+        let trait_id = match alias.id.lookup(db.upcast()).container {
+            ItemContainerId::TraitId(id) => id,
+            _ => unreachable!("non assoc type alias reached in normalize_trait_assoc_type()"),
+        };
+        let parent_subst = TyBuilder::subst_for_def(db, trait_id, None)
             .push(self.ty.clone())
             .fill(|x| {
                 // FIXME: this code is not covered in tests.
@@ -2953,6 +2967,8 @@ pub fn normalize_trait_assoc_type(
                 }
             })
             .build();
+        // FIXME: We don't handle GATs yet.
+        let projection = TyBuilder::assoc_type_projection(db, alias.id, Some(parent_subst)).build();
 
         let ty = db.normalize_projection(projection, self.env.clone());
         if ty.is_unknown() {
index 342912b678a1db836de2a77eb92f674fbc7246cd..07bae2b38c796b3ee6698ae09785e61e71bcf7a9 100644 (file)
@@ -22,7 +22,7 @@
     resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
     type_ref::Mutability,
     AsMacroCall, AssocItemId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, LocalFieldId,
-    Lookup, ModuleDefId, VariantId,
+    Lookup, ModuleDefId, TraitId, VariantId,
 };
 use hir_expand::{
     builtin_fn_macro::BuiltinFnLikeExpander,
@@ -302,10 +302,15 @@ pub(crate) fn resolve_await_to_poll(
             }
         }
 
+        let future_trait = db
+            .lang_item(self.resolver.krate(), hir_expand::name![future_trait].to_smol_str())?
+            .as_trait()?;
         let poll_fn = db
             .lang_item(self.resolver.krate(), hir_expand::name![poll].to_smol_str())?
             .as_function()?;
-        let substs = hir_ty::TyBuilder::subst_for_def(db, poll_fn).push(ty.clone()).build();
+        // HACK: subst for `poll()` coincides with that for `Future` because `poll()` itself
+        // doesn't have any generic parameters, so we skip building another subst for `poll()`.
+        let substs = hir_ty::TyBuilder::subst_for_def(db, future_trait, None).push(ty).build();
         Some(self.resolve_impl_method_or_trait_def(db, poll_fn, &substs))
     }
 
@@ -321,8 +326,10 @@ pub(crate) fn resolve_prefix_expr(
         };
         let ty = self.ty_of_expr(db, &prefix_expr.expr()?.into())?;
 
-        let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
-        let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
+        let (op_trait, op_fn) = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
+        // HACK: subst for all methods coincides with that for their trait because the methods
+        // don't have any generic parameters, so we skip building another subst for the methods.
+        let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
 
         Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
     }
@@ -337,8 +344,10 @@ pub(crate) fn resolve_index_expr(
 
         let lang_item_name = name![index];
 
-        let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
-        let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn)
+        let (op_trait, op_fn) = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
+        // HACK: subst for all methods coincides with that for their trait because the methods
+        // don't have any generic parameters, so we skip building another subst for the methods.
+        let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None)
             .push(base_ty.clone())
             .push(index_ty.clone())
             .build();
@@ -354,10 +363,14 @@ pub(crate) fn resolve_bin_expr(
         let lhs = self.ty_of_expr(db, &binop_expr.lhs()?.into())?;
         let rhs = self.ty_of_expr(db, &binop_expr.rhs()?.into())?;
 
-        let op_fn = lang_names_for_bin_op(op)
+        let (op_trait, op_fn) = lang_names_for_bin_op(op)
             .and_then(|(name, lang_item)| self.lang_trait_fn(db, &lang_item, &name))?;
-        let substs =
-            hir_ty::TyBuilder::subst_for_def(db, op_fn).push(lhs.clone()).push(rhs.clone()).build();
+        // HACK: subst for `index()` coincides with that for `Index` because `index()` itself
+        // doesn't have any generic parameters, so we skip building another subst for `index()`.
+        let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None)
+            .push(lhs.clone())
+            .push(rhs.clone())
+            .build();
 
         Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
     }
@@ -371,7 +384,13 @@ pub(crate) fn resolve_try_expr(
 
         let op_fn =
             db.lang_item(self.resolver.krate(), name![branch].to_smol_str())?.as_function()?;
-        let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
+        let op_trait = match op_fn.lookup(db.upcast()).container {
+            ItemContainerId::TraitId(id) => id,
+            _ => return None,
+        };
+        // HACK: subst for `branch()` coincides with that for `Try` because `branch()` itself
+        // doesn't have any generic parameters, so we skip building another subst for `branch()`.
+        let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
 
         Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
     }
@@ -799,9 +818,10 @@ fn lang_trait_fn(
         db: &dyn HirDatabase,
         lang_trait: &Name,
         method_name: &Name,
-    ) -> Option<FunctionId> {
-        db.trait_data(db.lang_item(self.resolver.krate(), lang_trait.to_smol_str())?.as_trait()?)
-            .method_by_name(method_name)
+    ) -> Option<(TraitId, FunctionId)> {
+        let trait_id = db.lang_item(self.resolver.krate(), lang_trait.to_smol_str())?.as_trait()?;
+        let fn_id = db.trait_data(trait_id).method_by_name(method_name)?;
+        Some((trait_id, fn_id))
     }
 
     fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> {