Skip to content

Commit 3981373

Browse files
committed
internal: add implicit Sized bounds to type parameters.
1 parent 8a84311 commit 3981373

File tree

7 files changed

+99
-21
lines changed

7 files changed

+99
-21
lines changed

crates/hir/src/display.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ impl HirDisplay for Function {
9393
} else {
9494
match &*data.ret_type {
9595
TypeRef::ImplTrait(bounds) => match bounds[0].as_ref() {
96-
TypeBound::Path(path) => {
96+
TypeBound::Path(path, _) => {
9797
path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings
9898
[0]
9999
.type_ref

crates/hir_def/src/generics.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -338,10 +338,6 @@ impl GenericParams {
338338
hrtb_lifetimes: Option<&Box<[Name]>>,
339339
target: Either<TypeRef, LifetimeRef>,
340340
) {
341-
if bound.question_mark_token().is_some() {
342-
// FIXME: remove this bound
343-
return;
344-
}
345341
let bound = TypeBound::from_ast(lower_ctx, bound);
346342
let predicate = match (target, bound) {
347343
(Either::Left(type_ref), bound) => match hrtb_lifetimes {

crates/hir_def/src/item_tree/lower.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use syntax::{
1010

1111
use crate::{
1212
generics::{GenericParams, TypeParamData, TypeParamProvenance},
13-
type_ref::{LifetimeRef, TraitRef},
13+
type_ref::{LifetimeRef, TraitBoundModifier, TraitRef},
1414
};
1515

1616
use super::*;
@@ -369,7 +369,7 @@ impl<'a> Ctx<'a> {
369369
let (ret_type, async_ret_type) = if func.async_token().is_some() {
370370
let async_ret_type = ret_type.clone();
371371
let future_impl = desugar_future_path(ret_type);
372-
let ty_bound = Interned::new(TypeBound::Path(future_impl));
372+
let ty_bound = Interned::new(TypeBound::Path(future_impl, TraitBoundModifier::None));
373373
(TypeRef::ImplTrait(vec![ty_bound]), Some(async_ret_type))
374374
} else {
375375
(ret_type, None)

crates/hir_def/src/item_tree/pretty.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::{
88
attr::RawAttrs,
99
generics::{WherePredicate, WherePredicateTypeTarget},
1010
path::GenericArg,
11+
type_ref::TraitBoundModifier,
1112
visibility::RawVisibility,
1213
};
1314

@@ -543,7 +544,13 @@ impl<'a> Printer<'a> {
543544
}
544545

545546
match bound.as_ref() {
546-
TypeBound::Path(path) => self.print_path(path),
547+
TypeBound::Path(path, modifier) => {
548+
match modifier {
549+
TraitBoundModifier::None => (),
550+
TraitBoundModifier::Maybe => w!(self, "?"),
551+
}
552+
self.print_path(path)
553+
}
547554
TypeBound::ForLifetime(lifetimes, path) => {
548555
w!(self, "for<{}> ", lifetimes.iter().format(", "));
549556
self.print_path(path);

crates/hir_def/src/type_ref.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,12 +118,20 @@ impl LifetimeRef {
118118

119119
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
120120
pub enum TypeBound {
121-
Path(Path),
121+
Path(Path, TraitBoundModifier),
122122
ForLifetime(Box<[Name]>, Path),
123123
Lifetime(LifetimeRef),
124124
Error,
125125
}
126126

127+
/// A modifier on a bound, currently this is only used for `?Sized`, where the
128+
/// modifier is `Maybe`.
129+
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
130+
pub enum TraitBoundModifier {
131+
None,
132+
Maybe,
133+
}
134+
127135
impl TypeRef {
128136
/// Converts an `ast::TypeRef` to a `hir::TypeRef`.
129137
pub fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self {
@@ -233,7 +241,7 @@ impl TypeRef {
233241
TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
234242
for bound in bounds {
235243
match bound.as_ref() {
236-
TypeBound::Path(path) | TypeBound::ForLifetime(_, path) => {
244+
TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
237245
go_path(path, f)
238246
}
239247
TypeBound::Lifetime(_) | TypeBound::Error => (),
@@ -265,7 +273,7 @@ impl TypeRef {
265273
}
266274
for bound in &binding.bounds {
267275
match bound.as_ref() {
268-
TypeBound::Path(path) | TypeBound::ForLifetime(_, path) => {
276+
TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
269277
go_path(path, f)
270278
}
271279
TypeBound::Lifetime(_) | TypeBound::Error => (),
@@ -295,7 +303,11 @@ impl TypeBound {
295303

296304
match node.kind() {
297305
ast::TypeBoundKind::PathType(path_type) => {
298-
lower_path_type(path_type).map(TypeBound::Path).unwrap_or(TypeBound::Error)
306+
let m = match node.question_mark_token() {
307+
Some(_) => TraitBoundModifier::Maybe,
308+
None => TraitBoundModifier::None,
309+
};
310+
lower_path_type(path_type).map(|p| TypeBound::Path(p, m)).unwrap_or(TypeBound::Error)
299311
}
300312
ast::TypeBoundKind::ForType(for_type) => {
301313
let lt_refs = match for_type.generic_param_list() {
@@ -322,7 +334,7 @@ impl TypeBound {
322334

323335
pub fn as_path(&self) -> Option<&Path> {
324336
match self {
325-
TypeBound::Path(p) | TypeBound::ForLifetime(_, p) => Some(p),
337+
TypeBound::Path(p, _) | TypeBound::ForLifetime(_, p) => Some(p),
326338
TypeBound::Lifetime(_) | TypeBound::Error => None,
327339
}
328340
}

crates/hir_ty/src/display.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use hir_def::{
1313
intern::{Internable, Interned},
1414
item_scope::ItemInNs,
1515
path::{Path, PathKind},
16-
type_ref::{TypeBound, TypeRef},
16+
type_ref::{TraitBoundModifier, TypeBound, TypeRef},
1717
visibility::Visibility,
1818
AssocContainerId, Lookup, ModuleId, TraitId,
1919
};
@@ -1026,7 +1026,14 @@ impl HirDisplay for TypeRef {
10261026
impl HirDisplay for TypeBound {
10271027
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
10281028
match self {
1029-
TypeBound::Path(path) => path.hir_fmt(f),
1029+
TypeBound::Path(path, modifier) => {
1030+
// todo don't print implicit Sized; implicit ?Sized on Self of a trait
1031+
match modifier {
1032+
TraitBoundModifier::None => (),
1033+
TraitBoundModifier::Maybe => write!(f, "?")?,
1034+
}
1035+
path.hir_fmt(f)
1036+
}
10301037
TypeBound::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
10311038
TypeBound::ForLifetime(lifetimes, path) => {
10321039
write!(f, "for<{}> ", lifetimes.iter().format(", "))?;

crates/hir_ty/src/lower.rs

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@ use hir_def::{
1818
generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
1919
path::{GenericArg, Path, PathSegment, PathSegments},
2020
resolver::{HasResolver, Resolver, TypeNs},
21-
type_ref::{TraitRef as HirTraitRef, TypeBound, TypeRef},
21+
type_ref::{TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef},
2222
AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId,
2323
GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
2424
TypeAliasId, TypeParamId, UnionId, VariantId,
2525
};
2626
use hir_expand::{name::Name, ExpandResult};
2727
use la_arena::ArenaMap;
28+
use rustc_hash::FxHashSet;
2829
use smallvec::SmallVec;
2930
use stdx::impl_from;
3031
use syntax::ast;
@@ -65,6 +66,8 @@ pub struct TyLoweringContext<'a> {
6566
/// Splitting this up would be a possible fix.
6667
opaque_type_data: RefCell<Vec<ReturnTypeImplTrait>>,
6768
expander: RefCell<Option<Expander>>,
69+
/// Keeps tracking types with explicit `?Sized` bounds.
70+
unsized_types: RefCell<FxHashSet<Ty>>,
6871
}
6972

7073
impl<'a> TyLoweringContext<'a> {
@@ -83,6 +86,7 @@ impl<'a> TyLoweringContext<'a> {
8386
type_param_mode,
8487
opaque_type_data,
8588
expander: RefCell::new(None),
89+
unsized_types: RefCell::default(),
8690
}
8791
}
8892

@@ -93,17 +97,20 @@ impl<'a> TyLoweringContext<'a> {
9397
) -> T {
9498
let opaque_ty_data_vec = self.opaque_type_data.replace(Vec::new());
9599
let expander = self.expander.replace(None);
100+
let unsized_types = self.unsized_types.replace(Default::default());
96101
let new_ctx = Self {
97102
in_binders: debruijn,
98103
impl_trait_counter: Cell::new(self.impl_trait_counter.get()),
99104
opaque_type_data: RefCell::new(opaque_ty_data_vec),
100105
expander: RefCell::new(expander),
106+
unsized_types: RefCell::new(unsized_types),
101107
..*self
102108
};
103109
let result = f(&new_ctx);
104110
self.impl_trait_counter.set(new_ctx.impl_trait_counter.get());
105111
self.opaque_type_data.replace(new_ctx.opaque_type_data.into_inner());
106112
self.expander.replace(new_ctx.expander.into_inner());
113+
self.unsized_types.replace(new_ctx.unsized_types.into_inner());
107114
result
108115
}
109116

@@ -778,10 +785,27 @@ impl<'a> TyLoweringContext<'a> {
778785
) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
779786
let mut bindings = None;
780787
let trait_ref = match bound {
781-
TypeBound::Path(path) => {
788+
TypeBound::Path(path, TraitBoundModifier::None) => {
782789
bindings = self.lower_trait_ref_from_path(path, Some(self_ty));
783790
bindings.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
784791
}
792+
TypeBound::Path(path, TraitBoundModifier::Maybe) => {
793+
let sized_trait = self
794+
.resolver
795+
.krate()
796+
.and_then(|krate| self.db.lang_item(krate, "sized".into()))
797+
.and_then(|lang_item| lang_item.as_trait());
798+
// Don't lower associated type bindings as the only possible relaxed trait bound
799+
// `?Sized` has none of them.
800+
// If we got another trait here ignore the bound completely.
801+
let trait_id = self
802+
.lower_trait_ref_from_path(path, Some(self_ty.clone()))
803+
.map(|trait_ref| trait_ref.hir_trait_id());
804+
if trait_id == sized_trait {
805+
self.unsized_types.borrow_mut().insert(self_ty);
806+
}
807+
None
808+
}
785809
TypeBound::ForLifetime(_, path) => {
786810
// FIXME Don't silently drop the hrtb lifetimes here
787811
bindings = self.lower_trait_ref_from_path(path, Some(self_ty));
@@ -804,8 +828,10 @@ impl<'a> TyLoweringContext<'a> {
804828
trait_ref: TraitRef,
805829
) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
806830
let last_segment = match bound {
807-
TypeBound::Path(path) | TypeBound::ForLifetime(_, path) => path.segments().last(),
808-
TypeBound::Error | TypeBound::Lifetime(_) => None,
831+
TypeBound::Path(path, TraitBoundModifier::None) | TypeBound::ForLifetime(_, path) => path.segments().last(),
832+
TypeBound::Path(_, TraitBoundModifier::Maybe)
833+
| TypeBound::Error
834+
| TypeBound::Lifetime(_) => None,
809835
};
810836
last_segment
811837
.into_iter()
@@ -1053,10 +1079,40 @@ pub(crate) fn generic_predicates_query(
10531079
let ctx =
10541080
TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
10551081
let generics = generics(db.upcast(), def);
1056-
resolver
1082+
1083+
let mut predicates = resolver
10571084
.where_predicates_in_scope()
10581085
.flat_map(|pred| ctx.lower_where_predicate(pred, false).map(|p| make_binders(&generics, p)))
1059-
.collect()
1086+
.collect::<Vec<_>>();
1087+
1088+
// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound.
1089+
// Exception is Self of a trait.
1090+
let is_trait_def = matches!(def, GenericDefId::TraitId(..));
1091+
let explicitly_unsized_tys = ctx.unsized_types.into_inner();
1092+
let subtsts = generics.bound_vars_subst(DebruijnIndex::INNERMOST);
1093+
let generic_args = &subtsts.as_slice(&Interner)[is_trait_def as usize..];
1094+
let sized_trait = resolver
1095+
.krate()
1096+
.and_then(|krate| db.lang_item(krate, "sized".into()))
1097+
.and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
1098+
let sized_predicates = sized_trait
1099+
.into_iter()
1100+
.flat_map(|sized_trait| {
1101+
let implicitly_sized_tys = generic_args
1102+
.iter()
1103+
.filter_map(|generic_arg| generic_arg.ty(&Interner))
1104+
.filter(|&self_ty| !explicitly_unsized_tys.contains(self_ty));
1105+
implicitly_sized_tys.map(move |self_ty| {
1106+
WhereClause::Implemented(TraitRef {
1107+
trait_id: sized_trait,
1108+
substitution: Substitution::from1(&Interner, self_ty.clone()),
1109+
})
1110+
})
1111+
})
1112+
.map(|p| make_binders(&generics, crate::wrap_empty_binders(p)));
1113+
1114+
predicates.extend(sized_predicates);
1115+
predicates.into()
10601116
}
10611117

10621118
/// Resolve the default type params from generics

0 commit comments

Comments
 (0)