mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-02 15:32:06 +00:00
Merge #9807
9807: Implicit `Sized` bounds r=iDawer a=iDawer This should close #8984 `hir_ty`: - Type parameters, associated types and `impl Trait` are `Sized` by deafault except `Self` in a trait. - Implicit `Sized` bound is added to end of predicate list. It does not check if such bound is present already. Also it does not track the bound is implicit. - Allowed ambiguous unsize coercion if Chalk returns definite guidance. - Allowed ambiguous autoderef if Chalk returns definite guidance. `hir_def`: - `ItemTree` pretty printing shows `?Sized` bounds. `HirDisplay`: - `impl Trait` with weird bounds rendered correctly. - `Sized`/`?Sized` bounds are not shown if they are default. ### Perf `./target/rust-analyzer-baseline_8a843113 -q analysis-stats --memory-usage .` ``` Database loaded: 1.63s, 287minstr, 91mb crates: 38, mods: 741, decls: 15914, fns: 11835 Item Collection: 26.80s, 73ginstr, 338mb exprs: 318994, ??ty: 398 (0%), ?ty: 435 (0%), !ty: 174 Inference: 50.28s, 116ginstr, 516mb Total: 77.08s, 189ginstr, 855mb ``` `./target/rust-analyzer-sized-fixed_ambig_coercion-de074fe6 -q analysis-stats --memory-usage .` ``` Database loaded: 1.63s, 287minstr, 91mb crates: 38, mods: 741, decls: 15914, fns: 11835 Item Collection: 26.95s, 73ginstr, 338mb exprs: 318994, ??ty: 398 (0%), ?ty: 435 (0%), !ty: 166 Inference: 96.39s, 234ginstr, 543mb Total: 123.33s, 307ginstr, 881mb ``` Co-authored-by: Dawer <7803845+iDawer@users.noreply.github.com>
This commit is contained in:
commit
baf1494374
@ -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};
|
||||
@ -93,7 +93,7 @@ impl HirDisplay for Function {
|
||||
} else {
|
||||
match &*data.ret_type {
|
||||
TypeRef::ImplTrait(bounds) => match bounds[0].as_ref() {
|
||||
TypeBound::Path(path) => {
|
||||
TypeBound::Path(path, _) => {
|
||||
path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings
|
||||
[0]
|
||||
.type_ref
|
||||
@ -239,7 +239,8 @@ 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)?;
|
||||
let default_sized = SizedByDefault::Sized { anchor: self.module(f.db).krate().id };
|
||||
write_bounds_like_dyn_trait_with_prefix(":", &predicates, default_sized, f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -338,10 +338,6 @@ impl GenericParams {
|
||||
hrtb_lifetimes: Option<&Box<[Name]>>,
|
||||
target: Either<TypeRef, LifetimeRef>,
|
||||
) {
|
||||
if bound.question_mark_token().is_some() {
|
||||
// FIXME: remove this bound
|
||||
return;
|
||||
}
|
||||
let bound = TypeBound::from_ast(lower_ctx, bound);
|
||||
let predicate = match (target, bound) {
|
||||
(Either::Left(type_ref), bound) => match hrtb_lifetimes {
|
||||
|
@ -10,7 +10,7 @@ use syntax::{
|
||||
|
||||
use crate::{
|
||||
generics::{GenericParams, TypeParamData, TypeParamProvenance},
|
||||
type_ref::{LifetimeRef, TraitRef},
|
||||
type_ref::{LifetimeRef, TraitBoundModifier, TraitRef},
|
||||
};
|
||||
|
||||
use super::*;
|
||||
@ -369,7 +369,7 @@ impl<'a> Ctx<'a> {
|
||||
let (ret_type, async_ret_type) = if func.async_token().is_some() {
|
||||
let async_ret_type = ret_type.clone();
|
||||
let future_impl = desugar_future_path(ret_type);
|
||||
let ty_bound = Interned::new(TypeBound::Path(future_impl));
|
||||
let ty_bound = Interned::new(TypeBound::Path(future_impl, TraitBoundModifier::None));
|
||||
(TypeRef::ImplTrait(vec![ty_bound]), Some(async_ret_type))
|
||||
} else {
|
||||
(ret_type, None)
|
||||
|
@ -8,6 +8,7 @@ use crate::{
|
||||
attr::RawAttrs,
|
||||
generics::{WherePredicate, WherePredicateTypeTarget},
|
||||
path::GenericArg,
|
||||
type_ref::TraitBoundModifier,
|
||||
visibility::RawVisibility,
|
||||
};
|
||||
|
||||
@ -543,7 +544,13 @@ impl<'a> Printer<'a> {
|
||||
}
|
||||
|
||||
match bound.as_ref() {
|
||||
TypeBound::Path(path) => self.print_path(path),
|
||||
TypeBound::Path(path, modifier) => {
|
||||
match modifier {
|
||||
TraitBoundModifier::None => (),
|
||||
TraitBoundModifier::Maybe => w!(self, "?"),
|
||||
}
|
||||
self.print_path(path)
|
||||
}
|
||||
TypeBound::ForLifetime(lifetimes, path) => {
|
||||
w!(self, "for<{}> ", lifetimes.iter().format(", "));
|
||||
self.print_path(path);
|
||||
|
@ -304,7 +304,7 @@ struct S<'a, 'b: 'a, T: Copy + 'a + 'b, const K: u8 = 0> {
|
||||
field: &'a &'b T,
|
||||
}
|
||||
|
||||
struct Tuple<T: Copy>(T);
|
||||
struct Tuple<T: Copy, U: ?Sized>(T, U);
|
||||
|
||||
impl<'a, 'b: 'a, T: Copy + 'a + 'b, const K: u8 = 0> S<'a, 'b, T, K> {
|
||||
fn f<G: 'a>(arg: impl Copy) -> impl Copy {}
|
||||
@ -325,11 +325,13 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {}
|
||||
pub(self) field: &'a &'b T,
|
||||
}
|
||||
|
||||
pub(self) struct Tuple<T>(
|
||||
pub(self) struct Tuple<T, U>(
|
||||
pub(self) 0: T,
|
||||
pub(self) 1: U,
|
||||
)
|
||||
where
|
||||
T: Copy;
|
||||
T: Copy,
|
||||
U: ?Sized;
|
||||
|
||||
impl<'a, 'b, T, const K: u8> S<'a, 'b, T, K>
|
||||
where
|
||||
|
@ -118,12 +118,20 @@ impl LifetimeRef {
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum TypeBound {
|
||||
Path(Path),
|
||||
Path(Path, TraitBoundModifier),
|
||||
ForLifetime(Box<[Name]>, Path),
|
||||
Lifetime(LifetimeRef),
|
||||
Error,
|
||||
}
|
||||
|
||||
/// A modifier on a bound, currently this is only used for `?Sized`, where the
|
||||
/// modifier is `Maybe`.
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum TraitBoundModifier {
|
||||
None,
|
||||
Maybe,
|
||||
}
|
||||
|
||||
impl TypeRef {
|
||||
/// Converts an `ast::TypeRef` to a `hir::TypeRef`.
|
||||
pub fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self {
|
||||
@ -233,7 +241,7 @@ impl TypeRef {
|
||||
TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
|
||||
for bound in bounds {
|
||||
match bound.as_ref() {
|
||||
TypeBound::Path(path) | TypeBound::ForLifetime(_, path) => {
|
||||
TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
|
||||
go_path(path, f)
|
||||
}
|
||||
TypeBound::Lifetime(_) | TypeBound::Error => (),
|
||||
@ -265,7 +273,7 @@ impl TypeRef {
|
||||
}
|
||||
for bound in &binding.bounds {
|
||||
match bound.as_ref() {
|
||||
TypeBound::Path(path) | TypeBound::ForLifetime(_, path) => {
|
||||
TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
|
||||
go_path(path, f)
|
||||
}
|
||||
TypeBound::Lifetime(_) | TypeBound::Error => (),
|
||||
@ -295,7 +303,13 @@ impl TypeBound {
|
||||
|
||||
match node.kind() {
|
||||
ast::TypeBoundKind::PathType(path_type) => {
|
||||
lower_path_type(path_type).map(TypeBound::Path).unwrap_or(TypeBound::Error)
|
||||
let m = match node.question_mark_token() {
|
||||
Some(_) => TraitBoundModifier::Maybe,
|
||||
None => TraitBoundModifier::None,
|
||||
};
|
||||
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() {
|
||||
@ -320,9 +334,10 @@ impl TypeBound {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_path(&self) -> Option<&Path> {
|
||||
pub fn as_path(&self) -> Option<(&Path, &TraitBoundModifier)> {
|
||||
match self {
|
||||
TypeBound::Path(p) | TypeBound::ForLifetime(_, p) => Some(p),
|
||||
TypeBound::Path(p, m) => Some((p, m)),
|
||||
TypeBound::ForLifetime(_, p) => Some((p, &TraitBoundModifier::None)),
|
||||
TypeBound::Lifetime(_) | TypeBound::Error => None,
|
||||
}
|
||||
}
|
||||
|
@ -14,8 +14,8 @@ use log::{info, warn};
|
||||
|
||||
use crate::{
|
||||
db::HirDatabase, static_lifetime, AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds,
|
||||
DebruijnIndex, Environment, InEnvironment, Interner, ProjectionTyExt, Solution, Substitution,
|
||||
Ty, TyBuilder, TyKind,
|
||||
ConstrainedSubst, DebruijnIndex, Environment, Guidance, InEnvironment, Interner,
|
||||
ProjectionTyExt, Solution, Substitution, Ty, TyBuilder, TyKind,
|
||||
};
|
||||
|
||||
const AUTODEREF_RECURSION_LIMIT: Limit = Limit::new(10);
|
||||
@ -187,7 +187,8 @@ fn deref_by_trait(
|
||||
let solution = db.trait_solve(krate, canonical)?;
|
||||
|
||||
match &solution {
|
||||
Solution::Unique(vars) => {
|
||||
Solution::Unique(Canonical { value: ConstrainedSubst { subst, .. }, binders })
|
||||
| Solution::Ambig(Guidance::Definite(Canonical { value: subst, binders })) => {
|
||||
// FIXME: vars may contain solutions for any inference variables
|
||||
// that happened to be inside ty. To correctly handle these, we
|
||||
// would have to pass the solution up to the inference context, but
|
||||
@ -203,8 +204,8 @@ fn deref_by_trait(
|
||||
// assumptions will be broken. We would need to properly introduce
|
||||
// new variables in that case
|
||||
|
||||
for i in 1..vars.binders.len(&Interner) {
|
||||
if vars.value.subst.at(&Interner, i - 1).assert_ty_ref(&Interner).kind(&Interner)
|
||||
for i in 1..binders.len(&Interner) {
|
||||
if subst.at(&Interner, i - 1).assert_ty_ref(&Interner).kind(&Interner)
|
||||
!= &TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, i - 1))
|
||||
{
|
||||
warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.goal, solution);
|
||||
@ -214,13 +215,11 @@ fn deref_by_trait(
|
||||
// FIXME: we remove lifetime variables here since they can confuse
|
||||
// the method resolution code later
|
||||
Some(fixup_lifetime_variables(Canonical {
|
||||
value: vars
|
||||
.value
|
||||
.subst
|
||||
.at(&Interner, vars.value.subst.len(&Interner) - 1)
|
||||
value: subst
|
||||
.at(&Interner, subst.len(&Interner) - 1)
|
||||
.assert_ty_ref(&Interner)
|
||||
.clone(),
|
||||
binders: vars.binders.clone(),
|
||||
binders: binders.clone(),
|
||||
}))
|
||||
}
|
||||
Solution::Ambig(_) => {
|
||||
|
@ -412,13 +412,28 @@ pub(crate) fn associated_ty_data_query(
|
||||
.with_type_param_mode(crate::lower::TypeParamLoweringMode::Variable);
|
||||
let self_ty =
|
||||
TyKind::BoundVar(BoundVar::new(crate::DebruijnIndex::INNERMOST, 0)).intern(&Interner);
|
||||
let bounds = type_alias_data
|
||||
let mut bounds: Vec<_> = type_alias_data
|
||||
.bounds
|
||||
.iter()
|
||||
.flat_map(|bound| ctx.lower_type_bound(bound, self_ty.clone(), false))
|
||||
.filter_map(|pred| generic_predicate_to_inline_bound(db, &pred, &self_ty))
|
||||
.collect();
|
||||
|
||||
if !ctx.unsized_types.borrow().contains(&self_ty) {
|
||||
let sized_trait = resolver
|
||||
.krate()
|
||||
.and_then(|krate| db.lang_item(krate, "sized".into()))
|
||||
.and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
|
||||
let sized_bound = sized_trait.into_iter().map(|sized_trait| {
|
||||
let trait_bound =
|
||||
rust_ir::TraitBound { trait_id: sized_trait, args_no_self: Default::default() };
|
||||
let inline_bound = rust_ir::InlineBound::TraitBound(trait_bound);
|
||||
chalk_ir::Binders::empty(&Interner, inline_bound)
|
||||
});
|
||||
bounds.extend(sized_bound);
|
||||
bounds.shrink_to_fit();
|
||||
}
|
||||
|
||||
// FIXME: Re-enable where clauses on associated types when an upstream chalk bug is fixed.
|
||||
// (rust-analyzer#9052)
|
||||
// let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars);
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
use std::fmt::{self, Debug};
|
||||
|
||||
use base_db::CrateId;
|
||||
use chalk_ir::BoundVar;
|
||||
use hir_def::{
|
||||
body,
|
||||
@ -13,9 +14,9 @@ use hir_def::{
|
||||
intern::{Internable, Interned},
|
||||
item_scope::ItemInNs,
|
||||
path::{Path, PathKind},
|
||||
type_ref::{TypeBound, TypeRef},
|
||||
type_ref::{TraitBoundModifier, TypeBound, TypeRef},
|
||||
visibility::Visibility,
|
||||
AssocContainerId, Lookup, ModuleId, TraitId,
|
||||
AssocContainerId, HasModule, Lookup, ModuleId, TraitId,
|
||||
};
|
||||
use hir_expand::{hygiene::Hygiene, name::Name};
|
||||
use itertools::Itertools;
|
||||
@ -376,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 contains_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(), contains_impl_fn(bounds))
|
||||
}
|
||||
TyKind::Alias(AliasTy::Opaque(OpaqueTy {
|
||||
opaque_ty_id,
|
||||
@ -389,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, contains_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, ")")?;
|
||||
@ -582,7 +614,13 @@ 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)?;
|
||||
let krate = func.lookup(f.db.upcast()).module(f.db.upcast()).krate();
|
||||
write_bounds_like_dyn_trait_with_prefix(
|
||||
"impl",
|
||||
bounds.skip_binders(),
|
||||
SizedByDefault::Sized { anchor: krate },
|
||||
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 +679,13 @@ impl HirDisplay for Ty {
|
||||
_ => false,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
write_bounds_like_dyn_trait_with_prefix("impl", &bounds, f)?;
|
||||
let krate = id.parent.module(f.db.upcast()).krate();
|
||||
write_bounds_like_dyn_trait_with_prefix(
|
||||
"impl",
|
||||
&bounds,
|
||||
SizedByDefault::Sized { anchor: krate },
|
||||
f,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -650,6 +694,7 @@ impl HirDisplay for Ty {
|
||||
write_bounds_like_dyn_trait_with_prefix(
|
||||
"dyn",
|
||||
dyn_ty.bounds.skip_binders().interned(),
|
||||
SizedByDefault::NotSized,
|
||||
f,
|
||||
)?;
|
||||
}
|
||||
@ -664,7 +709,13 @@ 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)?;
|
||||
let krate = func.lookup(f.db.upcast()).module(f.db.upcast()).krate();
|
||||
write_bounds_like_dyn_trait_with_prefix(
|
||||
"impl",
|
||||
bounds.skip_binders(),
|
||||
SizedByDefault::Sized { anchor: krate },
|
||||
f,
|
||||
)?;
|
||||
}
|
||||
ImplTraitId::AsyncBlockTypeImplTrait(..) => {
|
||||
write!(f, "{{async block}}")?;
|
||||
@ -713,15 +764,37 @@ fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = Trai
|
||||
utils::fn_traits(db, krate)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub enum SizedByDefault {
|
||||
NotSized,
|
||||
Sized { anchor: CrateId },
|
||||
}
|
||||
|
||||
impl SizedByDefault {
|
||||
fn is_sized_trait(self, trait_: TraitId, db: &dyn DefDatabase) -> bool {
|
||||
match self {
|
||||
Self::NotSized => false,
|
||||
Self::Sized { anchor } => {
|
||||
let sized_trait =
|
||||
db.lang_item(anchor, "sized".into()).and_then(|lang_item| lang_item.as_trait());
|
||||
Some(trait_) == sized_trait
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
if !predicates.is_empty()
|
||||
|| predicates.is_empty() && matches!(default_sized, SizedByDefault::Sized { .. })
|
||||
{
|
||||
write!(f, " ")?;
|
||||
write_bounds_like_dyn_trait(predicates, f)
|
||||
write_bounds_like_dyn_trait(predicates, default_sized, f)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
@ -729,6 +802,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 +814,18 @@ 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 = false;
|
||||
for p in predicates.iter() {
|
||||
match p.skip_binders() {
|
||||
WhereClause::Implemented(trait_ref) => {
|
||||
let trait_ = trait_ref.hir_trait_id();
|
||||
if default_sized.is_sized_trait(trait_, f.db.upcast()) {
|
||||
is_sized = true;
|
||||
if matches!(default_sized, SizedByDefault::Sized { .. }) {
|
||||
// Don't print +Sized, but rather +?Sized if absent.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if !is_fn_trait {
|
||||
is_fn_trait = fn_traits(f.db.upcast(), trait_).any(|it| it == trait_);
|
||||
}
|
||||
@ -808,6 +890,13 @@ fn write_bounds_like_dyn_trait(
|
||||
if angle_open {
|
||||
write!(f, ">")?;
|
||||
}
|
||||
if matches!(default_sized, SizedByDefault::Sized { .. }) {
|
||||
if !is_sized {
|
||||
write!(f, "{}?Sized", if first { "" } else { " + " })?;
|
||||
} else if first {
|
||||
write!(f, "Sized")?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -1026,7 +1115,13 @@ impl HirDisplay for TypeRef {
|
||||
impl HirDisplay for TypeBound {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
match self {
|
||||
TypeBound::Path(path) => path.hir_fmt(f),
|
||||
TypeBound::Path(path, modifier) => {
|
||||
match modifier {
|
||||
TraitBoundModifier::None => (),
|
||||
TraitBoundModifier::Maybe => write!(f, "?")?,
|
||||
}
|
||||
path.hir_fmt(f)
|
||||
}
|
||||
TypeBound::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
|
||||
TypeBound::ForLifetime(lifetimes, path) => {
|
||||
write!(f, "for<{}> ", lifetimes.iter().format(", "))?;
|
||||
|
@ -17,8 +17,8 @@ use crate::{
|
||||
Adjust, Adjustment, AutoBorrow, InferOk, InferResult, InferenceContext, OverloadedDeref,
|
||||
PointerCast, TypeError, TypeMismatch,
|
||||
},
|
||||
static_lifetime, Canonical, DomainGoal, FnPointer, FnSig, InEnvironment, Interner, Solution,
|
||||
Substitution, Ty, TyBuilder, TyExt, TyKind,
|
||||
static_lifetime, Canonical, DomainGoal, FnPointer, FnSig, Guidance, InEnvironment, Interner,
|
||||
Solution, Substitution, Ty, TyBuilder, TyExt, TyKind,
|
||||
};
|
||||
|
||||
pub(crate) type CoerceResult = Result<InferOk<(Vec<Adjustment>, Ty)>, TypeError>;
|
||||
@ -541,7 +541,7 @@ impl<'a> InferenceContext<'a> {
|
||||
_ => return Err(TypeError),
|
||||
};
|
||||
|
||||
let trait_ref = {
|
||||
let coerce_unsized_tref = {
|
||||
let b = TyBuilder::trait_ref(self.db, coerce_unsized_trait);
|
||||
if b.remaining() != 2 {
|
||||
// The CoerceUnsized trait should have two generic params: Self and T.
|
||||
@ -551,7 +551,7 @@ impl<'a> InferenceContext<'a> {
|
||||
};
|
||||
|
||||
let goal: InEnvironment<DomainGoal> =
|
||||
InEnvironment::new(&self.trait_env.env, trait_ref.cast(&Interner));
|
||||
InEnvironment::new(&self.trait_env.env, coerce_unsized_tref.cast(&Interner));
|
||||
|
||||
let canonicalized = self.canonicalize(goal);
|
||||
|
||||
@ -575,7 +575,9 @@ impl<'a> InferenceContext<'a> {
|
||||
},
|
||||
);
|
||||
}
|
||||
// FIXME: should we accept ambiguous results here?
|
||||
Solution::Ambig(Guidance::Definite(subst)) => {
|
||||
canonicalized.apply_solution(&mut self.table, subst)
|
||||
}
|
||||
_ => return Err(TypeError),
|
||||
};
|
||||
let unsize =
|
||||
|
@ -18,13 +18,14 @@ use hir_def::{
|
||||
generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
|
||||
path::{GenericArg, Path, PathSegment, PathSegments},
|
||||
resolver::{HasResolver, Resolver, TypeNs},
|
||||
type_ref::{TraitRef as HirTraitRef, TypeBound, TypeRef},
|
||||
type_ref::{TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef},
|
||||
AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId,
|
||||
GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
|
||||
TypeAliasId, TypeParamId, UnionId, VariantId,
|
||||
};
|
||||
use hir_expand::{name::Name, ExpandResult};
|
||||
use la_arena::ArenaMap;
|
||||
use rustc_hash::FxHashSet;
|
||||
use smallvec::SmallVec;
|
||||
use stdx::impl_from;
|
||||
use syntax::ast;
|
||||
@ -65,6 +66,8 @@ pub struct TyLoweringContext<'a> {
|
||||
/// Splitting this up would be a possible fix.
|
||||
opaque_type_data: RefCell<Vec<ReturnTypeImplTrait>>,
|
||||
expander: RefCell<Option<Expander>>,
|
||||
/// Tracks types with explicit `?Sized` bounds.
|
||||
pub(crate) unsized_types: RefCell<FxHashSet<Ty>>,
|
||||
}
|
||||
|
||||
impl<'a> TyLoweringContext<'a> {
|
||||
@ -83,6 +86,7 @@ impl<'a> TyLoweringContext<'a> {
|
||||
type_param_mode,
|
||||
opaque_type_data,
|
||||
expander: RefCell::new(None),
|
||||
unsized_types: RefCell::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,17 +97,20 @@ impl<'a> TyLoweringContext<'a> {
|
||||
) -> T {
|
||||
let opaque_ty_data_vec = self.opaque_type_data.replace(Vec::new());
|
||||
let expander = self.expander.replace(None);
|
||||
let unsized_types = self.unsized_types.replace(Default::default());
|
||||
let new_ctx = Self {
|
||||
in_binders: debruijn,
|
||||
impl_trait_counter: Cell::new(self.impl_trait_counter.get()),
|
||||
opaque_type_data: RefCell::new(opaque_ty_data_vec),
|
||||
expander: RefCell::new(expander),
|
||||
unsized_types: RefCell::new(unsized_types),
|
||||
..*self
|
||||
};
|
||||
let result = f(&new_ctx);
|
||||
self.impl_trait_counter.set(new_ctx.impl_trait_counter.get());
|
||||
self.opaque_type_data.replace(new_ctx.opaque_type_data.into_inner());
|
||||
self.expander.replace(new_ctx.expander.into_inner());
|
||||
self.unsized_types.replace(new_ctx.unsized_types.into_inner());
|
||||
result
|
||||
}
|
||||
|
||||
@ -219,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
|
||||
@ -238,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());
|
||||
@ -776,10 +783,27 @@ impl<'a> TyLoweringContext<'a> {
|
||||
) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
|
||||
let mut bindings = None;
|
||||
let trait_ref = match bound {
|
||||
TypeBound::Path(path) => {
|
||||
TypeBound::Path(path, TraitBoundModifier::None) => {
|
||||
bindings = self.lower_trait_ref_from_path(path, Some(self_ty));
|
||||
bindings.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
|
||||
}
|
||||
TypeBound::Path(path, TraitBoundModifier::Maybe) => {
|
||||
let sized_trait = self
|
||||
.resolver
|
||||
.krate()
|
||||
.and_then(|krate| self.db.lang_item(krate, "sized".into()))
|
||||
.and_then(|lang_item| lang_item.as_trait());
|
||||
// Don't lower associated type bindings as the only possible relaxed trait bound
|
||||
// `?Sized` has no of them.
|
||||
// If we got another trait here ignore the bound completely.
|
||||
let trait_id = self
|
||||
.lower_trait_ref_from_path(path, Some(self_ty.clone()))
|
||||
.map(|trait_ref| trait_ref.hir_trait_id());
|
||||
if trait_id == sized_trait {
|
||||
self.unsized_types.borrow_mut().insert(self_ty);
|
||||
}
|
||||
None
|
||||
}
|
||||
TypeBound::ForLifetime(_, path) => {
|
||||
// FIXME Don't silently drop the hrtb lifetimes here
|
||||
bindings = self.lower_trait_ref_from_path(path, Some(self_ty));
|
||||
@ -802,8 +826,12 @@ impl<'a> TyLoweringContext<'a> {
|
||||
trait_ref: TraitRef,
|
||||
) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
|
||||
let last_segment = match bound {
|
||||
TypeBound::Path(path) | TypeBound::ForLifetime(_, path) => path.segments().last(),
|
||||
TypeBound::Error | TypeBound::Lifetime(_) => None,
|
||||
TypeBound::Path(path, TraitBoundModifier::None) | TypeBound::ForLifetime(_, path) => {
|
||||
path.segments().last()
|
||||
}
|
||||
TypeBound::Path(_, TraitBoundModifier::Maybe)
|
||||
| TypeBound::Error
|
||||
| TypeBound::Lifetime(_) => None,
|
||||
};
|
||||
last_segment
|
||||
.into_iter()
|
||||
@ -843,13 +871,39 @@ 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);
|
||||
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
|
||||
});
|
||||
|
||||
ReturnTypeImplTrait { bounds: crate::make_only_type_binders(1, predicates) }
|
||||
}
|
||||
}
|
||||
@ -1008,7 +1062,7 @@ pub(crate) fn trait_environment_query(
|
||||
traits_in_scope
|
||||
.push((tr.self_type_parameter(&Interner).clone(), tr.hir_trait_id()));
|
||||
}
|
||||
let program_clause: chalk_ir::ProgramClause<Interner> = pred.clone().cast(&Interner);
|
||||
let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(&Interner);
|
||||
clauses.push(program_clause.into_from_env_clause(&Interner));
|
||||
}
|
||||
}
|
||||
@ -1035,6 +1089,15 @@ pub(crate) fn trait_environment_query(
|
||||
clauses.push(program_clause.into_from_env_clause(&Interner));
|
||||
}
|
||||
|
||||
let subst = generics(db.upcast(), def).type_params_subst(db);
|
||||
let explicitly_unsized_tys = ctx.unsized_types.into_inner();
|
||||
let implicitly_sized_clauses =
|
||||
implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver).map(|pred| {
|
||||
let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(&Interner);
|
||||
program_clause.into_from_env_clause(&Interner)
|
||||
});
|
||||
clauses.extend(implicitly_sized_clauses);
|
||||
|
||||
let krate = def.module(db.upcast()).krate();
|
||||
|
||||
let env = chalk_ir::Environment::new(&Interner).add_clauses(&Interner, clauses);
|
||||
@ -1051,10 +1114,49 @@ pub(crate) fn generic_predicates_query(
|
||||
let ctx =
|
||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
|
||||
let generics = generics(db.upcast(), def);
|
||||
resolver
|
||||
|
||||
let mut predicates = resolver
|
||||
.where_predicates_in_scope()
|
||||
.flat_map(|pred| ctx.lower_where_predicate(pred, false).map(|p| make_binders(&generics, p)))
|
||||
.collect()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let subst = generics.bound_vars_subst(DebruijnIndex::INNERMOST);
|
||||
let explicitly_unsized_tys = ctx.unsized_types.into_inner();
|
||||
let implicitly_sized_predicates =
|
||||
implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver)
|
||||
.map(|p| make_binders(&generics, crate::wrap_empty_binders(p)));
|
||||
predicates.extend(implicitly_sized_predicates);
|
||||
predicates.into()
|
||||
}
|
||||
|
||||
/// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound.
|
||||
/// Exception is Self of a trait def.
|
||||
fn implicitly_sized_clauses<'a>(
|
||||
db: &dyn HirDatabase,
|
||||
def: GenericDefId,
|
||||
explicitly_unsized_tys: &'a FxHashSet<Ty>,
|
||||
substitution: &'a Substitution,
|
||||
resolver: &Resolver,
|
||||
) -> impl Iterator<Item = WhereClause> + 'a {
|
||||
let is_trait_def = matches!(def, GenericDefId::TraitId(..));
|
||||
let generic_args = &substitution.as_slice(&Interner)[is_trait_def as usize..];
|
||||
let sized_trait = resolver
|
||||
.krate()
|
||||
.and_then(|krate| db.lang_item(krate, "sized".into()))
|
||||
.and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
|
||||
|
||||
sized_trait.into_iter().flat_map(move |sized_trait| {
|
||||
let implicitly_sized_tys = generic_args
|
||||
.iter()
|
||||
.filter_map(|generic_arg| generic_arg.ty(&Interner))
|
||||
.filter(move |&self_ty| !explicitly_unsized_tys.contains(self_ty));
|
||||
implicitly_sized_tys.map(move |self_ty| {
|
||||
WhereClause::Implemented(TraitRef {
|
||||
trait_id: sized_trait,
|
||||
substitution: Substitution::from1(&Interner, self_ty.clone()),
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Resolve the default type params from generics
|
||||
|
@ -398,15 +398,15 @@ fn test() {
|
||||
|
||||
#[test]
|
||||
fn coerce_unsize_apit() {
|
||||
// FIXME: #8984
|
||||
check(
|
||||
r#"
|
||||
//- minicore: coerce_unsized
|
||||
trait Foo {}
|
||||
|
||||
fn test(f: impl Foo) {
|
||||
fn test(f: impl Foo, g: &(impl Foo + ?Sized)) {
|
||||
let _: &dyn Foo = &f;
|
||||
//^^ expected &dyn Foo, got &impl Foo
|
||||
let _: &dyn Foo = g;
|
||||
//^ expected &dyn Foo, got &impl Foo + ?Sized
|
||||
}
|
||||
"#,
|
||||
);
|
||||
@ -559,3 +559,16 @@ fn test() {
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn coerce_type_var() {
|
||||
check_types(
|
||||
r#"
|
||||
//- minicore: from, coerce_unsized
|
||||
fn test() {
|
||||
let x = ();
|
||||
let _: &() = &x.into();
|
||||
} //^^^^^^^^ ()
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
@ -44,13 +44,13 @@ fn main() {
|
||||
fn render_raw_ptr_impl_ty() {
|
||||
check_types_source_code(
|
||||
r#"
|
||||
trait Sized {}
|
||||
//- minicore: sized
|
||||
trait Unpin {}
|
||||
fn foo() -> *const (impl Unpin + Sized) { loop {} }
|
||||
fn main() {
|
||||
let foo = foo();
|
||||
foo;
|
||||
} //^^^ *const (impl Unpin + Sized)
|
||||
} //^^^ *const impl Unpin
|
||||
"#,
|
||||
);
|
||||
}
|
||||
@ -67,3 +67,110 @@ fn foo(foo: &dyn for<'a> Foo<'a>) {}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sized_bounds_apit() {
|
||||
check_types_source_code(
|
||||
r#"
|
||||
//- minicore: 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>,
|
||||
ref_any: &impl ?Sized,
|
||||
empty: impl,
|
||||
) {
|
||||
a;
|
||||
//^ impl Foo
|
||||
b;
|
||||
//^ impl Foo
|
||||
c;
|
||||
//^ &impl Foo + ?Sized
|
||||
d;
|
||||
//^ S<impl Foo>
|
||||
ref_any;
|
||||
//^^^^^^^ &impl ?Sized
|
||||
empty;
|
||||
} //^^^^^ impl Sized
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sized_bounds_rpit() {
|
||||
check_types_source_code(
|
||||
r#"
|
||||
//- minicore: sized
|
||||
trait 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
|
||||
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)
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sized_bounds_impl_traits_in_fn_signature() {
|
||||
check_types_source_code(
|
||||
r#"
|
||||
//- minicore: 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
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -922,6 +922,7 @@ fn test() { foo.call(); }
|
||||
fn super_trait_impl_return_trait_method_resolution() {
|
||||
check_infer(
|
||||
r#"
|
||||
//- minicore: sized
|
||||
trait Base {
|
||||
fn foo(self) -> usize;
|
||||
}
|
||||
@ -1312,3 +1313,29 @@ impl<'a, T> IntoIterator for &'a [T] {
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sized_blanket_impl() {
|
||||
check_infer(
|
||||
r#"
|
||||
//- minicore: sized
|
||||
trait Foo { fn foo() -> u8; }
|
||||
impl<T: Sized> Foo for T {}
|
||||
fn f<S: Sized, T, U: ?Sized>() {
|
||||
u32::foo;
|
||||
S::foo;
|
||||
T::foo;
|
||||
U::foo;
|
||||
<[u32]>::foo;
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
89..160 '{ ...foo; }': ()
|
||||
95..103 'u32::foo': fn foo<u32>() -> u8
|
||||
109..115 'S::foo': fn foo<S>() -> u8
|
||||
121..127 'T::foo': fn foo<T>() -> u8
|
||||
133..139 'U::foo': {unknown}
|
||||
145..157 '<[u32]>::foo': {unknown}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -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 {} }
|
||||
|
@ -43,7 +43,7 @@ fn test() {
|
||||
fn infer_desugar_async() {
|
||||
check_types(
|
||||
r#"
|
||||
//- minicore: future
|
||||
//- minicore: future, sized
|
||||
async fn foo() -> u64 { 128 }
|
||||
|
||||
fn test() {
|
||||
@ -147,7 +147,7 @@ mod ops {
|
||||
pub use self::try_trait::Try;
|
||||
}
|
||||
|
||||
mov convert {
|
||||
mod convert {
|
||||
pub trait From<T> {}
|
||||
impl<T> From<T> for T {}
|
||||
}
|
||||
@ -567,8 +567,8 @@ fn deref_trait() {
|
||||
check_types(
|
||||
r#"
|
||||
//- minicore: deref
|
||||
struct Arc<T>;
|
||||
impl<T> core::ops::Deref for Arc<T> {
|
||||
struct Arc<T: ?Sized>;
|
||||
impl<T: ?Sized> core::ops::Deref for Arc<T> {
|
||||
type Target = T;
|
||||
}
|
||||
|
||||
@ -589,9 +589,9 @@ fn deref_trait_with_inference_var() {
|
||||
check_types(
|
||||
r#"
|
||||
//- minicore: deref
|
||||
struct Arc<T>;
|
||||
fn new_arc<T>() -> Arc<T> { Arc }
|
||||
impl<T> core::ops::Deref for Arc<T> {
|
||||
struct Arc<T: ?Sized>;
|
||||
fn new_arc<T: ?Sized>() -> Arc<T> { Arc }
|
||||
impl<T: ?Sized> core::ops::Deref for Arc<T> {
|
||||
type Target = T;
|
||||
}
|
||||
|
||||
@ -631,7 +631,7 @@ fn deref_trait_with_question_mark_size() {
|
||||
check_types(
|
||||
r#"
|
||||
//- minicore: deref
|
||||
struct Arc<T>;
|
||||
struct Arc<T: ?Sized>;
|
||||
impl<T: ?Sized> core::ops::Deref for Arc<T> {
|
||||
type Target = T;
|
||||
}
|
||||
@ -648,6 +648,25 @@ fn test(s: Arc<S>) {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deref_trait_with_implicit_sized_requirement_on_inference_var() {
|
||||
check_types(
|
||||
r#"
|
||||
//- minicore: deref
|
||||
struct Foo<T>;
|
||||
impl<T> core::ops::Deref for Foo<T> {
|
||||
type Target = ();
|
||||
}
|
||||
fn test() {
|
||||
let foo = Foo;
|
||||
*foo;
|
||||
//^^^^ ()
|
||||
let _: Foo<u8> = foo;
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn obligation_from_function_clause() {
|
||||
check_types(
|
||||
@ -845,6 +864,7 @@ fn test<T: ApplyL>(t: T) {
|
||||
fn argument_impl_trait() {
|
||||
check_infer_with_mismatches(
|
||||
r#"
|
||||
//- minicore: sized
|
||||
trait Trait<T> {
|
||||
fn foo(&self) -> T;
|
||||
fn foo2(&self) -> i64;
|
||||
@ -902,6 +922,7 @@ fn test(x: impl Trait<u64>, y: &impl Trait<u32>) {
|
||||
fn argument_impl_trait_type_args_1() {
|
||||
check_infer_with_mismatches(
|
||||
r#"
|
||||
//- minicore: sized
|
||||
trait Trait {}
|
||||
trait Foo {
|
||||
// this function has an implicit Self param, an explicit type param,
|
||||
@ -967,6 +988,7 @@ fn test() {
|
||||
fn argument_impl_trait_type_args_2() {
|
||||
check_infer_with_mismatches(
|
||||
r#"
|
||||
//- minicore: sized
|
||||
trait Trait {}
|
||||
struct S;
|
||||
impl Trait for S {}
|
||||
@ -1008,6 +1030,7 @@ fn test() {
|
||||
fn argument_impl_trait_to_fn_pointer() {
|
||||
check_infer_with_mismatches(
|
||||
r#"
|
||||
//- minicore: sized
|
||||
trait Trait {}
|
||||
fn foo(x: impl Trait) { loop {} }
|
||||
struct S;
|
||||
@ -1032,6 +1055,7 @@ fn test() {
|
||||
fn impl_trait() {
|
||||
check_infer(
|
||||
r#"
|
||||
//- minicore: sized
|
||||
trait Trait<T> {
|
||||
fn foo(&self) -> T;
|
||||
fn foo2(&self) -> i64;
|
||||
@ -1082,6 +1106,7 @@ fn simple_return_pos_impl_trait() {
|
||||
cov_mark::check!(lower_rpit);
|
||||
check_infer(
|
||||
r#"
|
||||
//- minicore: sized
|
||||
trait Trait<T> {
|
||||
fn foo(&self) -> T;
|
||||
}
|
||||
@ -1110,6 +1135,7 @@ fn test() {
|
||||
fn more_return_pos_impl_trait() {
|
||||
check_infer(
|
||||
r#"
|
||||
//- minicore: sized
|
||||
trait Iterator {
|
||||
type Item;
|
||||
fn next(&mut self) -> Self::Item;
|
||||
@ -1168,6 +1194,7 @@ fn test() {
|
||||
fn dyn_trait() {
|
||||
check_infer(
|
||||
r#"
|
||||
//- minicore: sized
|
||||
trait Trait<T> {
|
||||
fn foo(&self) -> T;
|
||||
fn foo2(&self) -> i64;
|
||||
@ -1217,6 +1244,7 @@ fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) {
|
||||
fn dyn_trait_in_impl() {
|
||||
check_infer(
|
||||
r#"
|
||||
//- minicore: sized
|
||||
trait Trait<T, U> {
|
||||
fn foo(&self) -> (T, U);
|
||||
}
|
||||
@ -1252,6 +1280,7 @@ fn test(s: S<u32, i32>) {
|
||||
fn dyn_trait_bare() {
|
||||
check_infer(
|
||||
r#"
|
||||
//- minicore: sized
|
||||
trait Trait {
|
||||
fn foo(&self) -> u64;
|
||||
}
|
||||
@ -1290,6 +1319,7 @@ fn test(x: Trait, y: &Trait) -> u64 {
|
||||
fn weird_bounds() {
|
||||
check_infer(
|
||||
r#"
|
||||
//- minicore: sized
|
||||
trait Trait {}
|
||||
fn test(
|
||||
a: impl Trait + 'lifetime,
|
||||
@ -1302,11 +1332,11 @@ fn test(
|
||||
"#,
|
||||
expect![[r#"
|
||||
28..29 'a': impl Trait
|
||||
59..60 'b': impl
|
||||
59..60 'b': impl Sized
|
||||
82..83 'c': impl Trait
|
||||
103..104 'd': impl
|
||||
128..129 'e': impl
|
||||
148..149 'f': impl Trait
|
||||
103..104 'd': impl Sized
|
||||
128..129 'e': impl ?Sized
|
||||
148..149 'f': impl Trait + ?Sized
|
||||
173..175 '{}': ()
|
||||
"#]],
|
||||
);
|
||||
@ -1331,6 +1361,7 @@ fn test(x: (impl Trait + UnknownTrait)) {
|
||||
fn assoc_type_bindings() {
|
||||
check_infer(
|
||||
r#"
|
||||
//- minicore: sized
|
||||
trait Trait {
|
||||
type Type;
|
||||
}
|
||||
@ -1495,6 +1526,7 @@ fn test<T: Trait1, U: Trait2>(x: T, y: U) {
|
||||
fn super_trait_impl_trait_method_resolution() {
|
||||
check_infer(
|
||||
r#"
|
||||
//- minicore: sized
|
||||
mod foo {
|
||||
trait SuperTrait {
|
||||
fn foo(&self) -> u32 {}
|
||||
@ -2299,6 +2331,7 @@ impl TokenStream for Rustc {
|
||||
fn unify_impl_trait() {
|
||||
check_infer_with_mismatches(
|
||||
r#"
|
||||
//- minicore: sized
|
||||
trait Trait<T> {}
|
||||
|
||||
fn foo(x: impl Trait<u32>) { loop {} }
|
||||
@ -2417,8 +2450,8 @@ fn dyn_trait_through_chalk() {
|
||||
check_types(
|
||||
r#"
|
||||
//- minicore: deref
|
||||
struct Box<T> {}
|
||||
impl<T> core::ops::Deref for Box<T> {
|
||||
struct Box<T: ?Sized> {}
|
||||
impl<T: ?Sized> core::ops::Deref for Box<T> {
|
||||
type Target = T;
|
||||
}
|
||||
trait Trait {
|
||||
@ -3515,3 +3548,33 @@ fn test() {
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn associated_type_sized_bounds() {
|
||||
check_infer(
|
||||
r#"
|
||||
//- minicore: sized
|
||||
struct Yes;
|
||||
trait IsSized { const IS_SIZED: Yes; }
|
||||
impl<T: Sized> IsSized for T { const IS_SIZED: Yes = Yes; }
|
||||
|
||||
trait Foo {
|
||||
type Explicit: Sized;
|
||||
type Implicit;
|
||||
type Relaxed: ?Sized;
|
||||
}
|
||||
fn f<F: Foo>() {
|
||||
F::Explicit::IS_SIZED;
|
||||
F::Implicit::IS_SIZED;
|
||||
F::Relaxed::IS_SIZED;
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
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}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ use hir_def::{
|
||||
intern::Interned,
|
||||
path::Path,
|
||||
resolver::{HasResolver, TypeNs},
|
||||
type_ref::TypeRef,
|
||||
type_ref::{TraitBoundModifier, TypeRef},
|
||||
AssocContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId,
|
||||
};
|
||||
use hir_expand::name::{name, Name};
|
||||
@ -58,6 +58,10 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
|
||||
},
|
||||
WherePredicate::Lifetime { .. } => None,
|
||||
})
|
||||
.filter_map(|(path, bound_modifier)| match bound_modifier {
|
||||
TraitBoundModifier::None => Some(path),
|
||||
TraitBoundModifier::Maybe => None,
|
||||
})
|
||||
.filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) {
|
||||
Some(TypeNs::TraitId(t)) => Some(t),
|
||||
_ => None,
|
||||
|
@ -1226,7 +1226,9 @@ fn main() {
|
||||
#[test]
|
||||
fn hover_for_param_with_multiple_traits() {
|
||||
check(
|
||||
r#"trait Deref {
|
||||
r#"
|
||||
//- minicore: sized
|
||||
trait Deref {
|
||||
type Target: ?Sized;
|
||||
}
|
||||
trait DerefMut {
|
||||
@ -3417,17 +3419,17 @@ fn foo() {
|
||||
fn hover_type_param() {
|
||||
check(
|
||||
r#"
|
||||
//- minicore: sized
|
||||
struct Foo<T>(T);
|
||||
trait Copy {}
|
||||
trait Clone {}
|
||||
trait Sized {}
|
||||
impl<T: Copy + Clone> Foo<T$0> where T: Sized {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
*T*
|
||||
|
||||
```rust
|
||||
T: Copy + Clone + Sized
|
||||
T: Copy + Clone
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
@ -3460,6 +3462,26 @@ impl<T: 'static> Foo<T$0> {}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hover_type_param_not_sized() {
|
||||
check(
|
||||
r#"
|
||||
//- minicore: sized
|
||||
struct Foo<T>(T);
|
||||
trait Copy {}
|
||||
trait Clone {}
|
||||
impl<T: Copy + Clone> Foo<T$0> where T: ?Sized {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
*T*
|
||||
|
||||
```rust
|
||||
T: Copy + Clone + ?Sized
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hover_const_param() {
|
||||
check(
|
||||
|
@ -924,9 +924,53 @@ fn main() {
|
||||
let foo = foo5();
|
||||
// ^^^ &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32
|
||||
let foo = foo6();
|
||||
// ^^^ impl Fn(f64, f64) -> u32 + Sized
|
||||
// ^^^ impl Fn(f64, f64) -> u32
|
||||
let foo = foo7();
|
||||
// ^^^ *const (impl Fn(f64, f64) -> u32 + Sized)
|
||||
// ^^^ *const impl Fn(f64, f64) -> u32
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[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()
|
||||
}
|
||||
"#,
|
||||
)
|
||||
|
@ -937,7 +937,8 @@ fn bar(worble: ()) ${0:-> ()} {
|
||||
fn add_function_with_impl_trait_arg() {
|
||||
check_assist(
|
||||
generate_function,
|
||||
r"
|
||||
r#"
|
||||
//- minicore: sized
|
||||
trait Foo {}
|
||||
fn foo() -> impl Foo {
|
||||
todo!()
|
||||
@ -945,8 +946,8 @@ fn foo() -> impl Foo {
|
||||
fn baz() {
|
||||
$0bar(foo())
|
||||
}
|
||||
",
|
||||
r"
|
||||
"#,
|
||||
r#"
|
||||
trait Foo {}
|
||||
fn foo() -> impl Foo {
|
||||
todo!()
|
||||
@ -958,7 +959,7 @@ fn baz() {
|
||||
fn bar(foo: impl Foo) ${0:-> ()} {
|
||||
todo!()
|
||||
}
|
||||
",
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user