internal: add implicit Sized
bounds to type parameters.
This commit is contained in:
parent
8a8431133e
commit
3981373b93
@ -93,7 +93,7 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
} else {
|
||||
match &*data.ret_type {
|
||||
TypeRef::ImplTrait(bounds) => match bounds[0].as_ref() {
|
||||
TypeBound::Path(path) => {
|
||||
TypeBound::Path(path, _) => {
|
||||
path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings
|
||||
[0]
|
||||
.type_ref
|
||||
|
@ -338,10 +338,6 @@ fn add_where_predicate_from_bound(
|
||||
hrtb_lifetimes: Option<&Box<[Name]>>,
|
||||
target: Either<TypeRef, LifetimeRef>,
|
||||
) {
|
||||
if bound.question_mark_token().is_some() {
|
||||
// FIXME: remove this bound
|
||||
return;
|
||||
}
|
||||
let bound = TypeBound::from_ast(lower_ctx, bound);
|
||||
let predicate = match (target, bound) {
|
||||
(Either::Left(type_ref), bound) => match hrtb_lifetimes {
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
use crate::{
|
||||
generics::{GenericParams, TypeParamData, TypeParamProvenance},
|
||||
type_ref::{LifetimeRef, TraitRef},
|
||||
type_ref::{LifetimeRef, TraitBoundModifier, TraitRef},
|
||||
};
|
||||
|
||||
use super::*;
|
||||
@ -369,7 +369,7 @@ fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>>
|
||||
let (ret_type, async_ret_type) = if func.async_token().is_some() {
|
||||
let async_ret_type = ret_type.clone();
|
||||
let future_impl = desugar_future_path(ret_type);
|
||||
let ty_bound = Interned::new(TypeBound::Path(future_impl));
|
||||
let ty_bound = Interned::new(TypeBound::Path(future_impl, TraitBoundModifier::None));
|
||||
(TypeRef::ImplTrait(vec![ty_bound]), Some(async_ret_type))
|
||||
} else {
|
||||
(ret_type, None)
|
||||
|
@ -8,6 +8,7 @@
|
||||
attr::RawAttrs,
|
||||
generics::{WherePredicate, WherePredicateTypeTarget},
|
||||
path::GenericArg,
|
||||
type_ref::TraitBoundModifier,
|
||||
visibility::RawVisibility,
|
||||
};
|
||||
|
||||
@ -543,7 +544,13 @@ fn print_type_bounds(&mut self, bounds: &[Interned<TypeBound>]) {
|
||||
}
|
||||
|
||||
match bound.as_ref() {
|
||||
TypeBound::Path(path) => self.print_path(path),
|
||||
TypeBound::Path(path, modifier) => {
|
||||
match modifier {
|
||||
TraitBoundModifier::None => (),
|
||||
TraitBoundModifier::Maybe => w!(self, "?"),
|
||||
}
|
||||
self.print_path(path)
|
||||
}
|
||||
TypeBound::ForLifetime(lifetimes, path) => {
|
||||
w!(self, "for<{}> ", lifetimes.iter().format(", "));
|
||||
self.print_path(path);
|
||||
|
@ -118,12 +118,20 @@ pub fn missing() -> LifetimeRef {
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum TypeBound {
|
||||
Path(Path),
|
||||
Path(Path, TraitBoundModifier),
|
||||
ForLifetime(Box<[Name]>, Path),
|
||||
Lifetime(LifetimeRef),
|
||||
Error,
|
||||
}
|
||||
|
||||
/// A modifier on a bound, currently this is only used for `?Sized`, where the
|
||||
/// modifier is `Maybe`.
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum TraitBoundModifier {
|
||||
None,
|
||||
Maybe,
|
||||
}
|
||||
|
||||
impl TypeRef {
|
||||
/// Converts an `ast::TypeRef` to a `hir::TypeRef`.
|
||||
pub fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self {
|
||||
@ -233,7 +241,7 @@ fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) {
|
||||
TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
|
||||
for bound in bounds {
|
||||
match bound.as_ref() {
|
||||
TypeBound::Path(path) | TypeBound::ForLifetime(_, path) => {
|
||||
TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
|
||||
go_path(path, f)
|
||||
}
|
||||
TypeBound::Lifetime(_) | TypeBound::Error => (),
|
||||
@ -265,7 +273,7 @@ fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef)) {
|
||||
}
|
||||
for bound in &binding.bounds {
|
||||
match bound.as_ref() {
|
||||
TypeBound::Path(path) | TypeBound::ForLifetime(_, path) => {
|
||||
TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
|
||||
go_path(path, f)
|
||||
}
|
||||
TypeBound::Lifetime(_) | TypeBound::Error => (),
|
||||
@ -295,7 +303,11 @@ pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::TypeBound) -> Self {
|
||||
|
||||
match node.kind() {
|
||||
ast::TypeBoundKind::PathType(path_type) => {
|
||||
lower_path_type(path_type).map(TypeBound::Path).unwrap_or(TypeBound::Error)
|
||||
let m = match node.question_mark_token() {
|
||||
Some(_) => TraitBoundModifier::Maybe,
|
||||
None => TraitBoundModifier::None,
|
||||
};
|
||||
lower_path_type(path_type).map(|p| TypeBound::Path(p, m)).unwrap_or(TypeBound::Error)
|
||||
}
|
||||
ast::TypeBoundKind::ForType(for_type) => {
|
||||
let lt_refs = match for_type.generic_param_list() {
|
||||
@ -322,7 +334,7 @@ pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::TypeBound) -> Self {
|
||||
|
||||
pub fn as_path(&self) -> Option<&Path> {
|
||||
match self {
|
||||
TypeBound::Path(p) | TypeBound::ForLifetime(_, p) => Some(p),
|
||||
TypeBound::Path(p, _) | TypeBound::ForLifetime(_, p) => Some(p),
|
||||
TypeBound::Lifetime(_) | TypeBound::Error => None,
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
intern::{Internable, Interned},
|
||||
item_scope::ItemInNs,
|
||||
path::{Path, PathKind},
|
||||
type_ref::{TypeBound, TypeRef},
|
||||
type_ref::{TraitBoundModifier, TypeBound, TypeRef},
|
||||
visibility::Visibility,
|
||||
AssocContainerId, Lookup, ModuleId, TraitId,
|
||||
};
|
||||
@ -1026,7 +1026,14 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
impl HirDisplay for TypeBound {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
match self {
|
||||
TypeBound::Path(path) => path.hir_fmt(f),
|
||||
TypeBound::Path(path, modifier) => {
|
||||
// todo don't print implicit Sized; implicit ?Sized on Self of a trait
|
||||
match modifier {
|
||||
TraitBoundModifier::None => (),
|
||||
TraitBoundModifier::Maybe => write!(f, "?")?,
|
||||
}
|
||||
path.hir_fmt(f)
|
||||
}
|
||||
TypeBound::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
|
||||
TypeBound::ForLifetime(lifetimes, path) => {
|
||||
write!(f, "for<{}> ", lifetimes.iter().format(", "))?;
|
||||
|
@ -18,13 +18,14 @@
|
||||
generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
|
||||
path::{GenericArg, Path, PathSegment, PathSegments},
|
||||
resolver::{HasResolver, Resolver, TypeNs},
|
||||
type_ref::{TraitRef as HirTraitRef, TypeBound, TypeRef},
|
||||
type_ref::{TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef},
|
||||
AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId,
|
||||
GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
|
||||
TypeAliasId, TypeParamId, UnionId, VariantId,
|
||||
};
|
||||
use hir_expand::{name::Name, ExpandResult};
|
||||
use la_arena::ArenaMap;
|
||||
use rustc_hash::FxHashSet;
|
||||
use smallvec::SmallVec;
|
||||
use stdx::impl_from;
|
||||
use syntax::ast;
|
||||
@ -65,6 +66,8 @@ pub struct TyLoweringContext<'a> {
|
||||
/// Splitting this up would be a possible fix.
|
||||
opaque_type_data: RefCell<Vec<ReturnTypeImplTrait>>,
|
||||
expander: RefCell<Option<Expander>>,
|
||||
/// Keeps tracking types with explicit `?Sized` bounds.
|
||||
unsized_types: RefCell<FxHashSet<Ty>>,
|
||||
}
|
||||
|
||||
impl<'a> TyLoweringContext<'a> {
|
||||
@ -83,6 +86,7 @@ pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver) -> Self {
|
||||
type_param_mode,
|
||||
opaque_type_data,
|
||||
expander: RefCell::new(None),
|
||||
unsized_types: RefCell::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,17 +97,20 @@ pub fn with_debruijn<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 new_ctx = Self {
|
||||
in_binders: debruijn,
|
||||
impl_trait_counter: Cell::new(self.impl_trait_counter.get()),
|
||||
opaque_type_data: RefCell::new(opaque_ty_data_vec),
|
||||
expander: RefCell::new(expander),
|
||||
unsized_types: RefCell::new(unsized_types),
|
||||
..*self
|
||||
};
|
||||
let result = f(&new_ctx);
|
||||
self.impl_trait_counter.set(new_ctx.impl_trait_counter.get());
|
||||
self.opaque_type_data.replace(new_ctx.opaque_type_data.into_inner());
|
||||
self.expander.replace(new_ctx.expander.into_inner());
|
||||
self.unsized_types.replace(new_ctx.unsized_types.into_inner());
|
||||
result
|
||||
}
|
||||
|
||||
@ -778,10 +785,27 @@ pub(crate) fn lower_type_bound(
|
||||
) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
|
||||
let mut bindings = None;
|
||||
let trait_ref = match bound {
|
||||
TypeBound::Path(path) => {
|
||||
TypeBound::Path(path, TraitBoundModifier::None) => {
|
||||
bindings = self.lower_trait_ref_from_path(path, Some(self_ty));
|
||||
bindings.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
|
||||
}
|
||||
TypeBound::Path(path, TraitBoundModifier::Maybe) => {
|
||||
let sized_trait = self
|
||||
.resolver
|
||||
.krate()
|
||||
.and_then(|krate| self.db.lang_item(krate, "sized".into()))
|
||||
.and_then(|lang_item| lang_item.as_trait());
|
||||
// Don't lower associated type bindings as the only possible relaxed trait bound
|
||||
// `?Sized` has none of them.
|
||||
// If we got another trait here ignore the bound completely.
|
||||
let trait_id = self
|
||||
.lower_trait_ref_from_path(path, Some(self_ty.clone()))
|
||||
.map(|trait_ref| trait_ref.hir_trait_id());
|
||||
if trait_id == sized_trait {
|
||||
self.unsized_types.borrow_mut().insert(self_ty);
|
||||
}
|
||||
None
|
||||
}
|
||||
TypeBound::ForLifetime(_, path) => {
|
||||
// FIXME Don't silently drop the hrtb lifetimes here
|
||||
bindings = self.lower_trait_ref_from_path(path, Some(self_ty));
|
||||
@ -804,8 +828,10 @@ fn assoc_type_bindings_from_type_bound(
|
||||
trait_ref: TraitRef,
|
||||
) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
|
||||
let last_segment = match bound {
|
||||
TypeBound::Path(path) | TypeBound::ForLifetime(_, path) => path.segments().last(),
|
||||
TypeBound::Error | TypeBound::Lifetime(_) => None,
|
||||
TypeBound::Path(path, TraitBoundModifier::None) | TypeBound::ForLifetime(_, path) => path.segments().last(),
|
||||
TypeBound::Path(_, TraitBoundModifier::Maybe)
|
||||
| TypeBound::Error
|
||||
| TypeBound::Lifetime(_) => None,
|
||||
};
|
||||
last_segment
|
||||
.into_iter()
|
||||
@ -1053,10 +1079,40 @@ pub(crate) fn generic_predicates_query(
|
||||
let ctx =
|
||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
|
||||
let generics = generics(db.upcast(), def);
|
||||
resolver
|
||||
|
||||
let mut predicates = resolver
|
||||
.where_predicates_in_scope()
|
||||
.flat_map(|pred| ctx.lower_where_predicate(pred, false).map(|p| make_binders(&generics, p)))
|
||||
.collect()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound.
|
||||
// Exception is Self of a trait.
|
||||
let is_trait_def = matches!(def, GenericDefId::TraitId(..));
|
||||
let explicitly_unsized_tys = ctx.unsized_types.into_inner();
|
||||
let subtsts = generics.bound_vars_subst(DebruijnIndex::INNERMOST);
|
||||
let generic_args = &subtsts.as_slice(&Interner)[is_trait_def as usize..];
|
||||
let sized_trait = resolver
|
||||
.krate()
|
||||
.and_then(|krate| db.lang_item(krate, "sized".into()))
|
||||
.and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
|
||||
let sized_predicates = sized_trait
|
||||
.into_iter()
|
||||
.flat_map(|sized_trait| {
|
||||
let implicitly_sized_tys = generic_args
|
||||
.iter()
|
||||
.filter_map(|generic_arg| generic_arg.ty(&Interner))
|
||||
.filter(|&self_ty| !explicitly_unsized_tys.contains(self_ty));
|
||||
implicitly_sized_tys.map(move |self_ty| {
|
||||
WhereClause::Implemented(TraitRef {
|
||||
trait_id: sized_trait,
|
||||
substitution: Substitution::from1(&Interner, self_ty.clone()),
|
||||
})
|
||||
})
|
||||
})
|
||||
.map(|p| make_binders(&generics, crate::wrap_empty_binders(p)));
|
||||
|
||||
predicates.extend(sized_predicates);
|
||||
predicates.into()
|
||||
}
|
||||
|
||||
/// Resolve the default type params from generics
|
||||
|
Loading…
Reference in New Issue
Block a user