path::{GenericArg, Path, PathSegment, PathSegments},
resolver::{HasResolver, Resolver, TypeNs},
type_ref::{TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef},
- AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId,
- GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
+ AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId,
+ HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
TypeAliasId, TypeParamId, UnionId, VariantId,
};
use hir_expand::{name::Name, ExpandResult};
use rustc_hash::FxHashSet;
use smallvec::SmallVec;
use stdx::impl_from;
-use syntax::ast;
+use syntax::{ast, SmolStr};
+use crate::all_super_traits;
use crate::{
consteval,
db::HirDatabase,
debruijn: DebruijnIndex,
f: impl FnOnce(&TyLoweringContext) -> T,
) -> T {
- let opaque_ty_data_vec = self.opaque_type_data.replace(Vec::new());
- let expander = self.expander.replace(None);
- let unsized_types = self.unsized_types.replace(Default::default());
+ let opaque_ty_data_vec = self.opaque_type_data.take();
+ let expander = self.expander.take();
+ let unsized_types = self.unsized_types.take();
let new_ctx = Self {
in_binders: debruijn,
impl_trait_counter: Cell::new(self.impl_trait_counter.get()),
let mut expander = self.expander.borrow_mut();
if expander.is_some() {
(Some(expander), false)
+ } else if let Some(module_id) = self.resolver.module() {
+ *expander =
+ Some(Expander::new(self.db.upcast(), macro_call.file_id, module_id));
+ (Some(expander), true)
} else {
- if let Some(module_id) = self.resolver.module() {
- *expander = Some(Expander::new(
- self.db.upcast(),
- macro_call.file_id,
- module_id,
- ));
- (Some(expander), true)
- } else {
- (None, false)
- }
+ (None, false)
}
};
let ty = if let Some(mut expander) = expander {
Some((it, None)) => it,
_ => return None,
};
- if let TypeNs::GenericParam(param_id) = resolution {
- Some(param_id)
- } else {
- None
+ match resolution {
+ TypeNs::GenericParam(param_id) => Some(param_id),
+ _ => None,
}
}
) -> (Ty, Option<TypeNs>) {
let ty = match resolution {
TypeNs::TraitId(trait_) => {
- let ty = if remaining_segments.len() == 1 {
- let trait_ref =
- self.lower_trait_ref_from_resolved_path(trait_, resolved_segment, None);
- let segment = remaining_segments.first().unwrap();
- let found = self
- .db
- .trait_data(trait_ref.hir_trait_id())
- .associated_type_by_name(segment.name);
- match found {
- Some(associated_ty) => {
- // FIXME handle type parameters on the segment
- TyKind::Alias(AliasTy::Projection(ProjectionTy {
- associated_ty_id: to_assoc_type_id(associated_ty),
- substitution: trait_ref.substitution,
- }))
- .intern(&Interner)
- }
- None => {
- // FIXME: report error (associated type not found)
- TyKind::Error.intern(&Interner)
+ let ty = match remaining_segments.len() {
+ 1 => {
+ let trait_ref =
+ self.lower_trait_ref_from_resolved_path(trait_, resolved_segment, None);
+ let segment = remaining_segments.first().unwrap();
+ let found = self
+ .db
+ .trait_data(trait_ref.hir_trait_id())
+ .associated_type_by_name(segment.name);
+ match found {
+ Some(associated_ty) => {
+ // FIXME handle type parameters on the segment
+ TyKind::Alias(AliasTy::Projection(ProjectionTy {
+ associated_ty_id: to_assoc_type_id(associated_ty),
+ substitution: trait_ref.substitution,
+ }))
+ .intern(&Interner)
+ }
+ None => {
+ // FIXME: report error (associated type not found)
+ TyKind::Error.intern(&Interner)
+ }
}
}
- } else if remaining_segments.len() > 1 {
- // FIXME report error (ambiguous associated type)
- TyKind::Error.intern(&Interner)
- } else {
- let self_ty = Some(
- TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
- .intern(&Interner),
- );
- let trait_ref = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
- ctx.lower_trait_ref_from_resolved_path(trait_, resolved_segment, self_ty)
- });
- let dyn_ty = DynTy {
- bounds: crate::make_only_type_binders(
- 1,
- QuantifiedWhereClauses::from_iter(
- &Interner,
- Some(crate::wrap_empty_binders(WhereClause::Implemented(
- trait_ref,
- ))),
+ 0 => {
+ let self_ty = Some(
+ TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
+ .intern(&Interner),
+ );
+ let trait_ref = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
+ ctx.lower_trait_ref_from_resolved_path(
+ trait_,
+ resolved_segment,
+ self_ty,
+ )
+ });
+ let dyn_ty = DynTy {
+ bounds: crate::make_only_type_binders(
+ 1,
+ QuantifiedWhereClauses::from_iter(
+ &Interner,
+ Some(crate::wrap_empty_binders(WhereClause::Implemented(
+ trait_ref,
+ ))),
+ ),
),
- ),
- lifetime: static_lifetime(),
- };
- TyKind::Dyn(dyn_ty).intern(&Interner)
+ lifetime: static_lifetime(),
+ };
+ TyKind::Dyn(dyn_ty).intern(&Interner)
+ }
+ _ => {
+ // FIXME report error (ambiguous associated type)
+ TyKind::Error.intern(&Interner)
+ }
};
return (ty, None);
}
fn select_associated_type(&self, res: Option<TypeNs>, segment: PathSegment<'_>) -> Ty {
if let Some(res) = res {
- let ty = associated_type_shorthand_candidates(
+ let ty = named_associated_type_shorthand_candidates(
self.db,
res,
+ Some(segment.name.clone()),
move |name, t, associated_ty| {
if name == segment.name {
let substs = match self.type_param_mode {
// associated_type_shorthand_candidates does not do that
let substs = substs.shifted_in_from(&Interner, self.in_binders);
// FIXME handle type parameters on the segment
- return Some(
+ Some(
TyKind::Alias(AliasTy::Projection(ProjectionTy {
associated_ty_id: to_assoc_type_id(associated_ty),
substitution: substs,
}))
.intern(&Interner),
- );
+ )
+ } else {
+ None
}
-
- None
},
);
// `Option::None::<T>` are both allowed (though the former is
// preferred). See also `def_ids_for_path_segments` in rustc.
let len = path.segments().len();
- let penultimate = if len >= 2 { path.segments().get(len - 2) } else { None };
+ let penultimate = len.checked_sub(2).and_then(|idx| path.segments().get(idx));
let segment = match penultimate {
Some(segment) if segment.args_and_bindings.is_some() => segment,
_ => last,
let sized_trait = self
.resolver
.krate()
- .and_then(|krate| self.db.lang_item(krate, "sized".into()))
+ .and_then(|krate| self.db.lang_item(krate, SmolStr::new_inline("sized")))
.and_then(|lang_item| lang_item.as_trait());
// Don't lower associated type bindings as the only possible relaxed trait bound
// `?Sized` has no of them.
};
last_segment
.into_iter()
- .flat_map(|segment| segment.args_and_bindings.into_iter())
- .flat_map(|args_and_bindings| args_and_bindings.bindings.iter())
+ .filter_map(|segment| segment.args_and_bindings)
+ .flat_map(|args_and_bindings| &args_and_bindings.bindings)
.flat_map(move |binding| {
let found = associated_type_by_name_including_super_traits(
self.db,
&binding.name,
);
let (super_trait_ref, associated_ty) = match found {
- None => return SmallVec::<[QuantifiedWhereClause; 1]>::new(),
+ None => return SmallVec::new(),
Some(t) => t,
};
let projection_ty = ProjectionTy {
associated_ty_id: to_assoc_type_id(associated_ty),
substitution: super_trait_ref.substitution,
};
- let mut preds = SmallVec::with_capacity(
+ let mut preds: SmallVec<[_; 1]> = SmallVec::with_capacity(
binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
);
if let Some(type_ref) = &binding.type_ref {
let krate = func.lookup(ctx.db.upcast()).module(ctx.db.upcast()).krate();
let sized_trait = ctx
.db
- .lang_item(krate, "sized".into())
+ .lang_item(krate, SmolStr::new_inline("sized"))
.and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
let sized_clause = sized_trait.map(|trait_id| {
let clause = WhereClause::Implemented(TraitRef {
pub fn associated_type_shorthand_candidates<R>(
db: &dyn HirDatabase,
res: TypeNs,
+ cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
+) -> Option<R> {
+ named_associated_type_shorthand_candidates(db, res, None, cb)
+}
+
+fn named_associated_type_shorthand_candidates<R>(
+ db: &dyn HirDatabase,
+ res: TypeNs,
+ assoc_name: Option<Name>,
mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
) -> Option<R> {
let mut search = |t| {
db.impl_trait(impl_id)?.into_value_and_skipped_binders().0,
),
TypeNs::GenericParam(param_id) => {
- let predicates = db.generic_predicates_for_param(param_id);
+ let predicates = db.generic_predicates_for_param(param_id, assoc_name);
let res = predicates.iter().find_map(|pred| match pred.skip_binders().skip_binders() {
// FIXME: how to correctly handle higher-ranked bounds here?
WhereClause::Implemented(tr) => search(
pub(crate) fn generic_predicates_for_param_query(
db: &dyn HirDatabase,
param_id: TypeParamId,
+ assoc_name: Option<Name>,
) -> Arc<[Binders<QuantifiedWhereClause>]> {
let resolver = param_id.parent.resolver(db.upcast());
let ctx =
TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
let generics = generics(db.upcast(), param_id.parent);
- resolver
+ let mut predicates: Vec<_> = resolver
.where_predicates_in_scope()
// we have to filter out all other predicates *first*, before attempting to lower them
.filter(|pred| match pred {
- WherePredicate::ForLifetime { target, .. }
- | WherePredicate::TypeBound { target, .. } => match target {
- WherePredicateTypeTarget::TypeRef(type_ref) => {
- ctx.lower_ty_only_param(type_ref) == Some(param_id)
+ WherePredicate::ForLifetime { target, bound, .. }
+ | WherePredicate::TypeBound { target, bound, .. } => {
+ match target {
+ WherePredicateTypeTarget::TypeRef(type_ref) => {
+ if ctx.lower_ty_only_param(type_ref) != Some(param_id) {
+ return false;
+ }
+ }
+ WherePredicateTypeTarget::TypeParam(local_id) => {
+ if *local_id != param_id.local_id {
+ return false;
+ }
+ }
+ };
+
+ match &**bound {
+ TypeBound::ForLifetime(_, path) | TypeBound::Path(path, _) => {
+ // Only lower the bound if the trait could possibly define the associated
+ // type we're looking for.
+
+ let assoc_name = match &assoc_name {
+ Some(it) => it,
+ None => return true,
+ };
+ let tr = match resolver
+ .resolve_path_in_type_ns_fully(db.upcast(), path.mod_path())
+ {
+ Some(TypeNs::TraitId(tr)) => tr,
+ _ => return false,
+ };
+
+ all_super_traits(db.upcast(), tr).iter().any(|tr| {
+ db.trait_data(*tr).items.iter().any(|(name, item)| {
+ matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name
+ })
+ })
+ }
+ TypeBound::Lifetime(_) | TypeBound::Error => false,
}
- WherePredicateTypeTarget::TypeParam(local_id) => *local_id == param_id.local_id,
- },
+ }
WherePredicate::Lifetime { .. } => false,
})
.flat_map(|pred| ctx.lower_where_predicate(pred, true).map(|p| make_binders(&generics, p)))
- .collect()
+ .collect();
+
+ let subst = generics.bound_vars_subst(DebruijnIndex::INNERMOST);
+ let explicitly_unsized_tys = ctx.unsized_types.into_inner();
+ let implicitly_sized_predicates =
+ implicitly_sized_clauses(db, param_id.parent, &explicitly_unsized_tys, &subst, &resolver)
+ .map(|p| make_binders(&generics, crate::wrap_empty_binders(p)));
+ predicates.extend(implicitly_sized_predicates);
+ predicates.into()
}
pub(crate) fn generic_predicates_for_param_recover(
_db: &dyn HirDatabase,
_cycle: &[String],
_param_id: &TypeParamId,
+ _assoc_name: &Option<Name>,
) -> Arc<[Binders<QuantifiedWhereClause>]> {
Arc::new([])
}
}
}
- let container: Option<AssocContainerId> = match def {
+ let container: Option<ItemContainerId> = match def {
// FIXME: is there a function for this?
GenericDefId::FunctionId(f) => Some(f.lookup(db.upcast()).container),
GenericDefId::AdtId(_) => None,
GenericDefId::EnumVariantId(_) => None,
GenericDefId::ConstId(c) => Some(c.lookup(db.upcast()).container),
};
- if let Some(AssocContainerId::TraitId(trait_id)) = container {
+ if let Some(ItemContainerId::TraitId(trait_id)) = container {
// add `Self: Trait<T1, T2, ...>` to the environment in trait
// function default implementations (and speculative code
// inside consts or type aliases)
let generic_args = &substitution.as_slice(&Interner)[is_trait_def as usize..];
let sized_trait = resolver
.krate()
- .and_then(|krate| db.lang_item(krate, "sized".into()))
+ .and_then(|krate| db.lang_item(krate, SmolStr::new_inline("sized")))
.and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
sized_trait.into_iter().flat_map(move |sized_trait| {
}
pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binders<Ty> {
+ let impl_loc = impl_id.lookup(db.upcast());
let impl_data = db.impl_data(impl_id);
let resolver = impl_id.resolver(db.upcast());
+ let _cx = stdx::panic_context::enter(format!(
+ "impl_self_ty_query({:?} -> {:?} -> {:?})",
+ impl_id, impl_loc, impl_data
+ ));
let generics = generics(db.upcast(), impl_id.into());
let ctx =
TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
}
pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> {
+ let impl_loc = impl_id.lookup(db.upcast());
let impl_data = db.impl_data(impl_id);
let resolver = impl_id.resolver(db.upcast());
+ let _cx = stdx::panic_context::enter(format!(
+ "impl_trait_query({:?} -> {:?} -> {:?})",
+ impl_id, impl_loc, impl_data
+ ));
let ctx =
TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders();