Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/lower.rs')
| -rw-r--r-- | crates/hir-ty/src/lower.rs | 193 |
1 files changed, 114 insertions, 79 deletions
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 82128ae658..0a4b1dfda1 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -306,7 +306,7 @@ impl<'a> TyLoweringContext<'a> { // 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 @@ impl<'a> TyLoweringContext<'a> { }; 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 @@ impl<'a> TyLoweringContext<'a> { .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 @@ impl<'a> TyLoweringContext<'a> { 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 @@ impl<'a> TyLoweringContext<'a> { // 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 @@ impl<'a> TyLoweringContext<'a> { 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 @@ impl<'a> TyLoweringContext<'a> { 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()) } }, ) |