mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-02 22:54:58 +00:00
HirDisplay prints ?Sized
bounds now; impl Trait: Sized
by default.
This commit is contained in:
parent
d9e6377b91
commit
421979bc68
5 changed files with 167 additions and 14 deletions
|
@ -7,7 +7,7 @@ use hir_def::{
|
||||||
};
|
};
|
||||||
use hir_ty::display::{
|
use hir_ty::display::{
|
||||||
write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError,
|
write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError,
|
||||||
HirFormatter,
|
HirFormatter, SizedByDefault,
|
||||||
};
|
};
|
||||||
use hir_ty::Interner;
|
use hir_ty::Interner;
|
||||||
use syntax::ast::{self, NameOwner};
|
use syntax::ast::{self, NameOwner};
|
||||||
|
@ -239,7 +239,7 @@ impl HirDisplay for TypeParam {
|
||||||
let predicates =
|
let predicates =
|
||||||
bounds.iter().cloned().map(|b| b.substitute(&Interner, &substs)).collect::<Vec<_>>();
|
bounds.iter().cloned().map(|b| b.substitute(&Interner, &substs)).collect::<Vec<_>>();
|
||||||
if !(predicates.is_empty() || f.omit_verbose_types()) {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -582,7 +582,12 @@ impl HirDisplay for Ty {
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
|
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
|
||||||
let bounds = data.substitute(&Interner, ¶meters);
|
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
|
// FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
|
||||||
}
|
}
|
||||||
ImplTraitId::AsyncBlockTypeImplTrait(..) => {
|
ImplTraitId::AsyncBlockTypeImplTrait(..) => {
|
||||||
|
@ -641,7 +646,12 @@ impl HirDisplay for Ty {
|
||||||
_ => false,
|
_ => false,
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.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(
|
write_bounds_like_dyn_trait_with_prefix(
|
||||||
"dyn",
|
"dyn",
|
||||||
dyn_ty.bounds.skip_binders().interned(),
|
dyn_ty.bounds.skip_binders().interned(),
|
||||||
|
SizedByDefault::NotSized,
|
||||||
f,
|
f,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
@ -664,7 +675,12 @@ impl HirDisplay for Ty {
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
|
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
|
||||||
let bounds = data.substitute(&Interner, &opaque_ty.substitution);
|
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(..) => {
|
ImplTraitId::AsyncBlockTypeImplTrait(..) => {
|
||||||
write!(f, "{{async block}}")?;
|
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)
|
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(
|
pub fn write_bounds_like_dyn_trait_with_prefix(
|
||||||
prefix: &str,
|
prefix: &str,
|
||||||
predicates: &[QuantifiedWhereClause],
|
predicates: &[QuantifiedWhereClause],
|
||||||
|
default_sized: SizedByDefault,
|
||||||
f: &mut HirFormatter,
|
f: &mut HirFormatter,
|
||||||
) -> Result<(), HirDisplayError> {
|
) -> Result<(), HirDisplayError> {
|
||||||
write!(f, "{}", prefix)?;
|
write!(f, "{}", prefix)?;
|
||||||
if !predicates.is_empty() {
|
if !predicates.is_empty() {
|
||||||
write!(f, " ")?;
|
write!(f, " ")?;
|
||||||
write_bounds_like_dyn_trait(predicates, f)
|
write_bounds_like_dyn_trait(predicates, default_sized, f)
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -729,6 +759,7 @@ pub fn write_bounds_like_dyn_trait_with_prefix(
|
||||||
|
|
||||||
fn write_bounds_like_dyn_trait(
|
fn write_bounds_like_dyn_trait(
|
||||||
predicates: &[QuantifiedWhereClause],
|
predicates: &[QuantifiedWhereClause],
|
||||||
|
default_sized: SizedByDefault,
|
||||||
f: &mut HirFormatter,
|
f: &mut HirFormatter,
|
||||||
) -> Result<(), HirDisplayError> {
|
) -> Result<(), HirDisplayError> {
|
||||||
// Note: This code is written to produce nice results (i.e.
|
// 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 first = true;
|
||||||
let mut angle_open = false;
|
let mut angle_open = false;
|
||||||
let mut is_fn_trait = false;
|
let mut is_fn_trait = false;
|
||||||
|
let mut is_sized = None;
|
||||||
for p in predicates.iter() {
|
for p in predicates.iter() {
|
||||||
match p.skip_binders() {
|
match p.skip_binders() {
|
||||||
WhereClause::Implemented(trait_ref) => {
|
WhereClause::Implemented(trait_ref) => {
|
||||||
let trait_ = trait_ref.hir_trait_id();
|
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 {
|
if !is_fn_trait {
|
||||||
is_fn_trait = fn_traits(f.db.upcast(), trait_).any(|it| it == 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 {
|
if angle_open {
|
||||||
write!(f, ">")?;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -226,6 +226,10 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
ImplTraitLoweringMode::Opaque => {
|
ImplTraitLoweringMode::Opaque => {
|
||||||
let idx = self.impl_trait_counter.get();
|
let idx = self.impl_trait_counter.get();
|
||||||
self.impl_trait_counter.set(idx + 1);
|
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());
|
assert!(idx as usize == self.opaque_type_data.borrow().len());
|
||||||
// this dance is to make sure the data is in the right
|
// this dance is to make sure the data is in the right
|
||||||
|
@ -245,14 +249,10 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
// away instead of two.
|
// away instead of two.
|
||||||
let actual_opaque_type_data = self
|
let actual_opaque_type_data = self
|
||||||
.with_debruijn(DebruijnIndex::INNERMOST, |ctx| {
|
.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;
|
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 impl_trait_id = ImplTraitId::ReturnTypeImplTrait(func, idx);
|
||||||
let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
|
let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
|
||||||
let generics = generics(self.db.upcast(), func.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);
|
cov_mark::hit!(lower_rpit);
|
||||||
let self_ty =
|
let self_ty =
|
||||||
TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(&Interner);
|
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| {
|
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) }
|
ReturnTypeImplTrait { bounds: crate::make_only_type_binders(1, predicates) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -406,7 +406,7 @@ trait Foo {}
|
||||||
fn test(f: impl Foo, g: &(impl Foo + ?Sized)) {
|
fn test(f: impl Foo, g: &(impl Foo + ?Sized)) {
|
||||||
let _: &dyn Foo = &f;
|
let _: &dyn Foo = &f;
|
||||||
let _: &dyn Foo = g;
|
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…
Add table
Add a link
Reference in a new issue