mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 04:44:57 +00:00
Account sized bounds in parentheses printing inside of ptr/ref of rpit.
This commit is contained in:
parent
d9ec88ea23
commit
14898729f4
7 changed files with 153 additions and 38 deletions
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
{
|
||||
return t.hir_fmt(f);
|
||||
}
|
||||
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, "?")?,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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 {} }
|
||||
|
|
|
@ -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}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue