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,
|
Some(_) => TraitBoundModifier::Maybe,
|
||||||
None => TraitBoundModifier::None,
|
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) => {
|
ast::TypeBoundKind::ForType(for_type) => {
|
||||||
let lt_refs = match for_type.generic_param_list() {
|
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...
|
// FIXME: all this just to decide whether to use parentheses...
|
||||||
let datas;
|
let conains_impl_fn = |bounds: &[QuantifiedWhereClause]| {
|
||||||
let predicates: Vec<_> = match t.kind(&Interner) {
|
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 => {
|
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 {
|
TyKind::Alias(AliasTy::Opaque(OpaqueTy {
|
||||||
opaque_ty_id,
|
opaque_ty_id,
|
||||||
|
@ -390,33 +400,54 @@ impl HirDisplay for Ty {
|
||||||
let impl_trait_id =
|
let impl_trait_id =
|
||||||
f.db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
|
f.db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
|
||||||
if let ImplTraitId::ReturnTypeImplTrait(func, idx) = impl_trait_id {
|
if let ImplTraitId::ReturnTypeImplTrait(func, idx) = impl_trait_id {
|
||||||
datas =
|
let datas =
|
||||||
f.db.return_type_impl_traits(func)
|
f.db.return_type_impl_traits(func)
|
||||||
.expect("impl trait id without data");
|
.expect("impl trait id without data");
|
||||||
let data = (*datas)
|
let data = (*datas)
|
||||||
.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, parameters);
|
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 {
|
} else {
|
||||||
Vec::new()
|
(0, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => Vec::new(),
|
_ => (0, false),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(WhereClause::Implemented(trait_ref)) =
|
if has_impl_fn_pred && preds_to_print <= 2 {
|
||||||
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);
|
return t.hir_fmt(f);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if predicates.len() > 1 {
|
if preds_to_print > 1 {
|
||||||
write!(f, "(")?;
|
write!(f, "(")?;
|
||||||
t.hir_fmt(f)?;
|
t.hir_fmt(f)?;
|
||||||
write!(f, ")")?;
|
write!(f, ")")?;
|
||||||
|
@ -1085,7 +1116,6 @@ impl HirDisplay for TypeBound {
|
||||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||||
match self {
|
match self {
|
||||||
TypeBound::Path(path, modifier) => {
|
TypeBound::Path(path, modifier) => {
|
||||||
// todo don't print implicit Sized; implicit ?Sized on Self of a trait
|
|
||||||
match modifier {
|
match modifier {
|
||||||
TraitBoundModifier::None => (),
|
TraitBoundModifier::None => (),
|
||||||
TraitBoundModifier::Maybe => write!(f, "?")?,
|
TraitBoundModifier::Maybe => write!(f, "?")?,
|
||||||
|
|
|
@ -828,7 +828,9 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
trait_ref: TraitRef,
|
trait_ref: TraitRef,
|
||||||
) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
|
) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
|
||||||
let last_segment = match bound {
|
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::Path(_, TraitBoundModifier::Maybe)
|
||||||
| TypeBound::Error
|
| TypeBound::Error
|
||||||
| TypeBound::Lifetime(_) => None,
|
| TypeBound::Lifetime(_) => None,
|
||||||
|
|
|
@ -42,16 +42,15 @@ fn main() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn render_raw_ptr_impl_ty() {
|
fn render_raw_ptr_impl_ty() {
|
||||||
// FIXME: remove parens, they apper because there is an implicit Sized bound
|
|
||||||
check_types_source_code(
|
check_types_source_code(
|
||||||
r#"
|
r#"
|
||||||
//- minicore: sized
|
//- minicore: sized
|
||||||
trait Unpin {}
|
trait Unpin {}
|
||||||
fn foo() -> *const impl Unpin { loop {} }
|
fn foo() -> *const (impl Unpin + Sized) { loop {} }
|
||||||
fn main() {
|
fn main() {
|
||||||
let foo = foo();
|
let foo = foo();
|
||||||
foo;
|
foo;
|
||||||
} //^^^ *const (impl Unpin)
|
} //^^^ *const impl Unpin
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -94,9 +93,9 @@ fn test(
|
||||||
d;
|
d;
|
||||||
//^ S<impl Foo>
|
//^ S<impl Foo>
|
||||||
ref_any;
|
ref_any;
|
||||||
//^ &impl ?Sized
|
//^^^^^^^ &impl ?Sized
|
||||||
empty;
|
empty;
|
||||||
} //^ impl Sized
|
} //^^^^^ impl Sized
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -107,11 +106,50 @@ fn sized_bounds_rpit() {
|
||||||
r#"
|
r#"
|
||||||
//- minicore: sized
|
//- minicore: sized
|
||||||
trait Foo {}
|
trait Foo {}
|
||||||
fn foo() -> impl Foo { loop {} }
|
fn foo1() -> impl Foo { loop {} }
|
||||||
fn test<T: Foo>() {
|
fn foo2() -> impl Foo + Sized { loop {} }
|
||||||
let foo = foo();
|
fn foo3() -> impl Foo + ?Sized { loop {} }
|
||||||
|
fn test() {
|
||||||
|
let foo = foo1();
|
||||||
foo;
|
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#"
|
r#"
|
||||||
//- minicore: deref
|
//- minicore: deref
|
||||||
struct Box<T: ?Sized> {}
|
struct Box<T: ?Sized> {}
|
||||||
impl<T> core::ops::Deref for Box<T> {
|
impl<T: ?Sized> core::ops::Deref for Box<T> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
|
@ -1063,6 +1063,7 @@ fn cfg_tail() {
|
||||||
fn impl_trait_in_option_9530() {
|
fn impl_trait_in_option_9530() {
|
||||||
check_types(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
|
//- minicore: sized
|
||||||
struct Option<T>;
|
struct Option<T>;
|
||||||
impl<T> Option<T> {
|
impl<T> Option<T> {
|
||||||
fn unwrap(self) -> T { loop {} }
|
fn unwrap(self) -> T { loop {} }
|
||||||
|
|
|
@ -3534,9 +3534,7 @@ fn test() {
|
||||||
fn associated_type_sized_bounds() {
|
fn associated_type_sized_bounds() {
|
||||||
check_infer(
|
check_infer(
|
||||||
r#"
|
r#"
|
||||||
#[lang = "sized"]
|
//- minicore: sized
|
||||||
pub trait Sized {}
|
|
||||||
|
|
||||||
struct Yes;
|
struct Yes;
|
||||||
trait IsSized { const IS_SIZED: Yes; }
|
trait IsSized { const IS_SIZED: Yes; }
|
||||||
impl<T: Sized> IsSized for T { const IS_SIZED: Yes = Yes; }
|
impl<T: Sized> IsSized for T { const IS_SIZED: Yes = Yes; }
|
||||||
|
@ -3553,11 +3551,11 @@ fn f<F: Foo>() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
142..145 'Yes': Yes
|
104..107 'Yes': Yes
|
||||||
250..333 '{ ...ZED; }': ()
|
212..295 '{ ...ZED; }': ()
|
||||||
256..277 'F::Exp..._SIZED': Yes
|
218..239 'F::Exp..._SIZED': Yes
|
||||||
283..304 'F::Imp..._SIZED': Yes
|
245..266 'F::Imp..._SIZED': Yes
|
||||||
310..330 'F::Rel..._SIZED': {unknown}
|
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]
|
#[test]
|
||||||
fn unit_structs_have_no_type_hints() {
|
fn unit_structs_have_no_type_hints() {
|
||||||
check_types(
|
check_types(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue