HirDisplay prints ?Sized
bounds now; impl Trait: Sized
by default.
This commit is contained in:
parent
d9e6377b91
commit
421979bc68
@ -7,7 +7,7 @@ use hir_def::{
|
||||
};
|
||||
use hir_ty::display::{
|
||||
write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError,
|
||||
HirFormatter,
|
||||
HirFormatter, SizedByDefault,
|
||||
};
|
||||
use hir_ty::Interner;
|
||||
use syntax::ast::{self, NameOwner};
|
||||
@ -239,7 +239,7 @@ impl HirDisplay for TypeParam {
|
||||
let predicates =
|
||||
bounds.iter().cloned().map(|b| b.substitute(&Interner, &substs)).collect::<Vec<_>>();
|
||||
if !(predicates.is_empty() || f.omit_verbose_types()) {
|
||||
write_bounds_like_dyn_trait_with_prefix(":", &predicates, f)?;
|
||||
write_bounds_like_dyn_trait_with_prefix(":", &predicates, SizedByDefault::Sized, f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -582,7 +582,12 @@ impl HirDisplay for Ty {
|
||||
.as_ref()
|
||||
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
|
||||
let bounds = data.substitute(&Interner, ¶meters);
|
||||
write_bounds_like_dyn_trait_with_prefix("impl", bounds.skip_binders(), f)?;
|
||||
write_bounds_like_dyn_trait_with_prefix(
|
||||
"impl",
|
||||
bounds.skip_binders(),
|
||||
SizedByDefault::Sized,
|
||||
f,
|
||||
)?;
|
||||
// FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
|
||||
}
|
||||
ImplTraitId::AsyncBlockTypeImplTrait(..) => {
|
||||
@ -641,7 +646,12 @@ impl HirDisplay for Ty {
|
||||
_ => false,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
write_bounds_like_dyn_trait_with_prefix("impl", &bounds, f)?;
|
||||
write_bounds_like_dyn_trait_with_prefix(
|
||||
"impl",
|
||||
&bounds,
|
||||
SizedByDefault::Sized,
|
||||
f,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -650,6 +660,7 @@ impl HirDisplay for Ty {
|
||||
write_bounds_like_dyn_trait_with_prefix(
|
||||
"dyn",
|
||||
dyn_ty.bounds.skip_binders().interned(),
|
||||
SizedByDefault::NotSized,
|
||||
f,
|
||||
)?;
|
||||
}
|
||||
@ -664,7 +675,12 @@ impl HirDisplay for Ty {
|
||||
.as_ref()
|
||||
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
|
||||
let bounds = data.substitute(&Interner, &opaque_ty.substitution);
|
||||
write_bounds_like_dyn_trait_with_prefix("impl", bounds.skip_binders(), f)?;
|
||||
write_bounds_like_dyn_trait_with_prefix(
|
||||
"impl",
|
||||
bounds.skip_binders(),
|
||||
SizedByDefault::Sized,
|
||||
f,
|
||||
)?;
|
||||
}
|
||||
ImplTraitId::AsyncBlockTypeImplTrait(..) => {
|
||||
write!(f, "{{async block}}")?;
|
||||
@ -713,15 +729,29 @@ fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = Trai
|
||||
utils::fn_traits(db, krate)
|
||||
}
|
||||
|
||||
fn is_sized_trait(db: &dyn DefDatabase, trait_: TraitId) -> Option<bool> {
|
||||
let krate = trait_.lookup(db).container.krate();
|
||||
let sized_trait =
|
||||
db.lang_item(krate, "sized".into()).and_then(|lang_item| lang_item.as_trait())?;
|
||||
Some(trait_ == sized_trait)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub enum SizedByDefault {
|
||||
NotSized,
|
||||
Sized,
|
||||
}
|
||||
|
||||
pub fn write_bounds_like_dyn_trait_with_prefix(
|
||||
prefix: &str,
|
||||
predicates: &[QuantifiedWhereClause],
|
||||
default_sized: SizedByDefault,
|
||||
f: &mut HirFormatter,
|
||||
) -> Result<(), HirDisplayError> {
|
||||
write!(f, "{}", prefix)?;
|
||||
if !predicates.is_empty() {
|
||||
write!(f, " ")?;
|
||||
write_bounds_like_dyn_trait(predicates, f)
|
||||
write_bounds_like_dyn_trait(predicates, default_sized, f)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
@ -729,6 +759,7 @@ pub fn write_bounds_like_dyn_trait_with_prefix(
|
||||
|
||||
fn write_bounds_like_dyn_trait(
|
||||
predicates: &[QuantifiedWhereClause],
|
||||
default_sized: SizedByDefault,
|
||||
f: &mut HirFormatter,
|
||||
) -> Result<(), HirDisplayError> {
|
||||
// Note: This code is written to produce nice results (i.e.
|
||||
@ -740,10 +771,22 @@ fn write_bounds_like_dyn_trait(
|
||||
let mut first = true;
|
||||
let mut angle_open = false;
|
||||
let mut is_fn_trait = false;
|
||||
let mut is_sized = None;
|
||||
for p in predicates.iter() {
|
||||
match p.skip_binders() {
|
||||
WhereClause::Implemented(trait_ref) => {
|
||||
let trait_ = trait_ref.hir_trait_id();
|
||||
match is_sized_trait(f.db.upcast(), trait_) {
|
||||
Some(true) => {
|
||||
is_sized = Some(true);
|
||||
if default_sized == SizedByDefault::Sized {
|
||||
// Don't print +Sized, but rather +?Sized if absent.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Some(false) => is_sized = is_sized.or(Some(false)),
|
||||
None => (),
|
||||
}
|
||||
if !is_fn_trait {
|
||||
is_fn_trait = fn_traits(f.db.upcast(), trait_).any(|it| it == trait_);
|
||||
}
|
||||
@ -808,6 +851,13 @@ fn write_bounds_like_dyn_trait(
|
||||
if angle_open {
|
||||
write!(f, ">")?;
|
||||
}
|
||||
if default_sized == SizedByDefault::Sized && is_sized.is_some() {
|
||||
if is_sized == Some(false) {
|
||||
write!(f, "{}?Sized", if first { "" } else { " + " })?;
|
||||
} else if first {
|
||||
write!(f, "Sized")?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -226,6 +226,10 @@ impl<'a> TyLoweringContext<'a> {
|
||||
ImplTraitLoweringMode::Opaque => {
|
||||
let idx = self.impl_trait_counter.get();
|
||||
self.impl_trait_counter.set(idx + 1);
|
||||
let func = match self.resolver.generic_def() {
|
||||
Some(GenericDefId::FunctionId(f)) => f,
|
||||
_ => panic!("opaque impl trait lowering in non-function"),
|
||||
};
|
||||
|
||||
assert!(idx as usize == self.opaque_type_data.borrow().len());
|
||||
// this dance is to make sure the data is in the right
|
||||
@ -245,14 +249,10 @@ impl<'a> TyLoweringContext<'a> {
|
||||
// away instead of two.
|
||||
let actual_opaque_type_data = self
|
||||
.with_debruijn(DebruijnIndex::INNERMOST, |ctx| {
|
||||
ctx.lower_impl_trait(bounds)
|
||||
ctx.lower_impl_trait(bounds, func)
|
||||
});
|
||||
self.opaque_type_data.borrow_mut()[idx as usize] = actual_opaque_type_data;
|
||||
|
||||
let func = match self.resolver.generic_def() {
|
||||
Some(GenericDefId::FunctionId(f)) => f,
|
||||
_ => panic!("opaque impl trait lowering in non-function"),
|
||||
};
|
||||
let impl_trait_id = ImplTraitId::ReturnTypeImplTrait(func, idx);
|
||||
let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
|
||||
let generics = generics(self.db.upcast(), func.into());
|
||||
@ -871,13 +871,42 @@ impl<'a> TyLoweringContext<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
fn lower_impl_trait(&self, bounds: &[Interned<TypeBound>]) -> ReturnTypeImplTrait {
|
||||
fn lower_impl_trait(
|
||||
&self,
|
||||
bounds: &[Interned<TypeBound>],
|
||||
func: FunctionId,
|
||||
) -> ReturnTypeImplTrait {
|
||||
cov_mark::hit!(lower_rpit);
|
||||
let self_ty =
|
||||
TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(&Interner);
|
||||
// XXX(iDawer): Can shifting mess with unsized_types? For now I better reinsure.
|
||||
let outer_unsized_types = self.unsized_types.replace(Default::default());
|
||||
let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
|
||||
bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)).collect()
|
||||
let mut predicates: Vec<_> = bounds
|
||||
.iter()
|
||||
.flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false))
|
||||
.collect();
|
||||
|
||||
if !ctx.unsized_types.borrow().contains(&self_ty) {
|
||||
let krate = func.lookup(ctx.db.upcast()).module(ctx.db.upcast()).krate();
|
||||
let sized_trait = ctx
|
||||
.db
|
||||
.lang_item(krate, "sized".into())
|
||||
.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 {
|
||||
trait_id,
|
||||
substitution: Substitution::from1(&Interner, self_ty.clone()),
|
||||
});
|
||||
crate::wrap_empty_binders(clause)
|
||||
});
|
||||
predicates.extend(sized_clause.into_iter());
|
||||
predicates.shrink_to_fit();
|
||||
}
|
||||
predicates
|
||||
});
|
||||
self.unsized_types.replace(outer_unsized_types);
|
||||
|
||||
ReturnTypeImplTrait { bounds: crate::make_only_type_binders(1, predicates) }
|
||||
}
|
||||
}
|
||||
|
@ -406,7 +406,7 @@ trait Foo {}
|
||||
fn test(f: impl Foo, g: &(impl Foo + ?Sized)) {
|
||||
let _: &dyn Foo = &f;
|
||||
let _: &dyn Foo = g;
|
||||
//^ expected &dyn Foo, got &impl Foo
|
||||
//^ expected &dyn Foo, got &impl Foo + ?Sized
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
@ -67,3 +67,77 @@ fn foo(foo: &dyn for<'a> Foo<'a>) {}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sized_bounds_apit() {
|
||||
check_types_source_code(
|
||||
r#"
|
||||
#[lang = "sized"]
|
||||
pub trait Sized {}
|
||||
|
||||
trait Foo {}
|
||||
trait Bar<T> {}
|
||||
struct S<T>;
|
||||
fn test(
|
||||
a: impl Foo,
|
||||
b: impl Foo + Sized,
|
||||
c: &(impl Foo + ?Sized),
|
||||
d: S<impl Foo>,
|
||||
e: impl Bar<impl Foo>,
|
||||
empty: impl,
|
||||
) {
|
||||
a;
|
||||
//^ impl Foo
|
||||
b;
|
||||
//^ impl Foo
|
||||
c;
|
||||
//^ &impl Foo + ?Sized
|
||||
d;
|
||||
//^ S<impl Foo>
|
||||
e;
|
||||
//^ impl Bar<impl Foo>
|
||||
empty;
|
||||
} //^ impl Sized
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sized_bounds_rpit() {
|
||||
check_types_source_code(
|
||||
r#"
|
||||
#[lang = "sized"]
|
||||
pub trait Sized {}
|
||||
|
||||
trait Foo {}
|
||||
fn foo() -> impl Foo { loop {} }
|
||||
fn test<T: Foo>() {
|
||||
let foo = foo();
|
||||
foo;
|
||||
} //^ impl Foo
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sized_bounds_impl_traits_in_fn_signature() {
|
||||
check_types_source_code(
|
||||
r#"
|
||||
#[lang = "sized"]
|
||||
pub trait Sized {}
|
||||
|
||||
trait Foo {}
|
||||
fn test(
|
||||
a: fn(impl Foo) -> impl Foo,
|
||||
b: fn(impl Foo + Sized) -> impl Foo + Sized,
|
||||
c: fn(&(impl Foo + ?Sized)) -> &(impl Foo + ?Sized),
|
||||
) {
|
||||
a;
|
||||
//^ fn(impl Foo) -> impl Foo
|
||||
b;
|
||||
//^ fn(impl Foo) -> impl Foo
|
||||
c;
|
||||
} //^ fn(&impl Foo + ?Sized) -> &impl Foo + ?Sized
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user