Account sized bounds in parentheses printing inside of ptr/ref of rpit.

This commit is contained in:
Dawer 2021-08-03 17:01:00 +05:00
parent d9ec88ea23
commit 14898729f4
7 changed files with 153 additions and 38 deletions

View file

@ -307,7 +307,9 @@ impl TypeBound {
Some(_) => TraitBoundModifier::Maybe,
None => TraitBoundModifier::None,
};
lower_path_type(path_type).map(|p| TypeBound::Path(p, m)).unwrap_or(TypeBound::Error)
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() {

View file

@ -377,10 +377,20 @@ impl HirDisplay for Ty {
}
// FIXME: all this just to decide whether to use parentheses...
let datas;
let predicates: Vec<_> = match t.kind(&Interner) {
let conains_impl_fn = |bounds: &[QuantifiedWhereClause]| {
bounds.iter().any(|bound| {
if let WhereClause::Implemented(trait_ref) = bound.skip_binders() {
let trait_ = trait_ref.hir_trait_id();
fn_traits(f.db.upcast(), trait_).any(|it| it == trait_)
} else {
false
}
})
};
let (preds_to_print, has_impl_fn_pred) = match t.kind(&Interner) {
TyKind::Dyn(dyn_ty) if dyn_ty.bounds.skip_binders().interned().len() > 1 => {
dyn_ty.bounds.skip_binders().interned().iter().cloned().collect()
let bounds = dyn_ty.bounds.skip_binders().interned();
(bounds.len(), conains_impl_fn(bounds))
}
TyKind::Alias(AliasTy::Opaque(OpaqueTy {
opaque_ty_id,
@ -390,33 +400,54 @@ impl HirDisplay for Ty {
let impl_trait_id =
f.db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
if let ImplTraitId::ReturnTypeImplTrait(func, idx) = impl_trait_id {
datas =
let datas =
f.db.return_type_impl_traits(func)
.expect("impl trait id without data");
let data = (*datas)
.as_ref()
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
let bounds = data.substitute(&Interner, parameters);
bounds.into_value_and_skipped_binders().0
let mut len = bounds.skip_binders().len();
// Don't count Sized but count when it absent
// (i.e. when explicit ?Sized bound is set).
let default_sized = SizedByDefault::Sized {
anchor: func.lookup(f.db.upcast()).module(f.db.upcast()).krate(),
};
let sized_bounds = bounds
.skip_binders()
.iter()
.filter(|b| {
matches!(
b.skip_binders(),
WhereClause::Implemented(trait_ref)
if default_sized.is_sized_trait(
trait_ref.hir_trait_id(),
f.db.upcast(),
),
)
})
.count();
match sized_bounds {
0 => len += 1,
_ => {
len = len.saturating_sub(sized_bounds);
}
}
(len, conains_impl_fn(bounds.skip_binders()))
} else {
Vec::new()
(0, false)
}
}
_ => Vec::new(),
_ => (0, false),
};
if let Some(WhereClause::Implemented(trait_ref)) =
predicates.get(0).map(|b| b.skip_binders())
{
let trait_ = trait_ref.hir_trait_id();
if fn_traits(f.db.upcast(), trait_).any(|it| it == trait_)
&& predicates.len() <= 2
{
if has_impl_fn_pred && preds_to_print <= 2 {
return t.hir_fmt(f);
}
}
if predicates.len() > 1 {
if preds_to_print > 1 {
write!(f, "(")?;
t.hir_fmt(f)?;
write!(f, ")")?;
@ -1085,7 +1116,6 @@ impl HirDisplay for TypeBound {
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
match self {
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, "?")?,

View file

@ -828,7 +828,9 @@ impl<'a> TyLoweringContext<'a> {
trait_ref: TraitRef,
) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
let last_segment = match bound {
TypeBound::Path(path, TraitBoundModifier::None) | TypeBound::ForLifetime(_, path) => path.segments().last(),
TypeBound::Path(path, TraitBoundModifier::None) | TypeBound::ForLifetime(_, path) => {
path.segments().last()
}
TypeBound::Path(_, TraitBoundModifier::Maybe)
| TypeBound::Error
| TypeBound::Lifetime(_) => None,

View file

@ -42,16 +42,15 @@ fn main() {
#[test]
fn render_raw_ptr_impl_ty() {
// FIXME: remove parens, they apper because there is an implicit Sized bound
check_types_source_code(
r#"
//- minicore: sized
trait Unpin {}
fn foo() -> *const impl Unpin { loop {} }
fn foo() -> *const (impl Unpin + Sized) { loop {} }
fn main() {
let foo = foo();
foo;
} //^^^ *const (impl Unpin)
} //^^^ *const impl Unpin
"#,
);
}
@ -94,9 +93,9 @@ fn test(
d;
//^ S<impl Foo>
ref_any;
//^ &impl ?Sized
//^^^^^^^ &impl ?Sized
empty;
} //^ impl Sized
} //^^^^^ impl Sized
"#,
);
}
@ -107,11 +106,50 @@ fn sized_bounds_rpit() {
r#"
//- minicore: sized
trait Foo {}
fn foo() -> impl Foo { loop {} }
fn test<T: Foo>() {
let foo = foo();
fn foo1() -> impl Foo { loop {} }
fn foo2() -> impl Foo + Sized { loop {} }
fn foo3() -> impl Foo + ?Sized { loop {} }
fn test() {
let foo = foo1();
foo;
} //^ impl Foo
//^^^ impl Foo
let foo = foo2();
foo;
//^^^ impl Foo
let foo = foo3();
foo;
} //^^^ impl Foo + ?Sized
"#,
);
}
#[test]
fn parenthesize_ptr_rpit_sized_bounds() {
check_types_source_code(
r#"
//- minicore: sized
trait Foo {}
fn foo1() -> *const impl Foo { loop {} }
fn foo2() -> *const (impl Foo + Sized) { loop {} }
fn foo3() -> *const (impl Sized + Foo) { loop {} }
fn foo4() -> *const (impl Foo + ?Sized) { loop {} }
fn foo5() -> *const (impl ?Sized + Foo) { loop {} }
fn test() {
let foo = foo1();
foo;
//^^^ *const impl Foo
let foo = foo2();
foo;
//^^^ *const impl Foo
let foo = foo3();
foo;
//^^^ *const impl Foo
let foo = foo4();
foo;
//^^^ *const (impl Foo + ?Sized)
let foo = foo5();
foo;
} //^^^ *const (impl Foo + ?Sized)
"#,
);
}

View file

@ -944,7 +944,7 @@ fn lifetime_from_chalk_during_deref() {
r#"
//- minicore: deref
struct Box<T: ?Sized> {}
impl<T> core::ops::Deref for Box<T> {
impl<T: ?Sized> core::ops::Deref for Box<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
@ -1063,6 +1063,7 @@ fn cfg_tail() {
fn impl_trait_in_option_9530() {
check_types(
r#"
//- minicore: sized
struct Option<T>;
impl<T> Option<T> {
fn unwrap(self) -> T { loop {} }

View file

@ -3534,9 +3534,7 @@ fn test() {
fn associated_type_sized_bounds() {
check_infer(
r#"
#[lang = "sized"]
pub trait Sized {}
//- minicore: sized
struct Yes;
trait IsSized { const IS_SIZED: Yes; }
impl<T: Sized> IsSized for T { const IS_SIZED: Yes = Yes; }
@ -3553,11 +3551,11 @@ fn f<F: Foo>() {
}
"#,
expect![[r#"
142..145 'Yes': Yes
250..333 '{ ...ZED; }': ()
256..277 'F::Exp..._SIZED': Yes
283..304 'F::Imp..._SIZED': Yes
310..330 'F::Rel..._SIZED': {unknown}
104..107 'Yes': Yes
212..295 '{ ...ZED; }': ()
218..239 'F::Exp..._SIZED': Yes
245..266 'F::Imp..._SIZED': Yes
272..292 'F::Rel..._SIZED': {unknown}
"#]],
);
}

View file

@ -932,6 +932,50 @@ fn main() {
)
}
#[test]
fn fn_hints_ptr_rpit_fn_parentheses() {
check_types(
r#"
//- minicore: fn, sized
trait Trait {}
fn foo1() -> *const impl Fn() { loop {} }
fn foo2() -> *const (impl Fn() + Sized) { loop {} }
fn foo3() -> *const (impl Fn() + ?Sized) { loop {} }
fn foo4() -> *const (impl Sized + Fn()) { loop {} }
fn foo5() -> *const (impl ?Sized + Fn()) { loop {} }
fn foo6() -> *const (impl Fn() + Trait) { loop {} }
fn foo7() -> *const (impl Fn() + Sized + Trait) { loop {} }
fn foo8() -> *const (impl Fn() + ?Sized + Trait) { loop {} }
fn foo9() -> *const (impl Fn() -> u8 + ?Sized) { loop {} }
fn foo10() -> *const (impl Fn() + Sized + ?Sized) { loop {} }
fn main() {
let foo = foo1();
// ^^^ *const impl Fn()
let foo = foo2();
// ^^^ *const impl Fn()
let foo = foo3();
// ^^^ *const (impl Fn() + ?Sized)
let foo = foo4();
// ^^^ *const impl Fn()
let foo = foo5();
// ^^^ *const (impl Fn() + ?Sized)
let foo = foo6();
// ^^^ *const (impl Fn() + Trait)
let foo = foo7();
// ^^^ *const (impl Fn() + Trait)
let foo = foo8();
// ^^^ *const (impl Fn() + Trait + ?Sized)
let foo = foo9();
// ^^^ *const (impl Fn() -> u8 + ?Sized)
let foo = foo10();
// ^^^ *const impl Fn()
}
"#,
)
}
#[test]
fn unit_structs_have_no_type_hints() {
check_types(