Skip to content

Commit 1915980

Browse files
committed
fix: Fix impl Trait<Self> causing stackoverflows
1 parent 2cbc284 commit 1915980

11 files changed

Lines changed: 228 additions & 144 deletions

File tree

‎Cargo.toml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ smol_str.opt-level = 3
2222
text-size.opt-level = 3
2323
# This speeds up `cargo xtask dist`.
2424
miniz_oxide.opt-level = 3
25+
salsa.opt-level = 3
2526

2627
[profile.release]
2728
incremental = true

‎crates/hir-ty/src/display.rs‎

Lines changed: 118 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use intern::{Internable, Interned};
2828
use itertools::Itertools;
2929
use la_arena::ArenaMap;
3030
use smallvec::SmallVec;
31-
use stdx::never;
31+
use stdx::{never,IsNoneOr};
3232
use triomphe::Arc;
3333

3434
usecrate::{
@@ -41,9 +41,9 @@ use crate::{
4141
mir::pad16,
4242
primitive, to_assoc_type_id,
4343
utils::{self, detect_variant_from_bytes, generics,ClosureSubst},
44-
AdtId,AliasEq,AliasTy,Binders,CallableDefId,CallableSig,Const,ConstScalar,ConstValue,
45-
DomainGoal,FnAbi,GenericArg,GenericArgData,ImplTraitId,Interner,Lifetime,LifetimeData,
46-
LifetimeOutlives,MemoryMap,Mutability,OpaqueTy,ProjectionTy,ProjectionTyExt,
44+
AdtId,AliasEq,AliasTy,Binders,CallableDefId,CallableSig,ConcreteConst,Const,
45+
ConstScalar,ConstValue,DomainGoal,FnAbi,GenericArg,ImplTraitId,Interner,Lifetime,
46+
LifetimeData,LifetimeOutlives,MemoryMap,Mutability,OpaqueTy,ProjectionTy,ProjectionTyExt,
4747
QuantifiedWhereClause,Scalar,Substitution,TraitEnvironment,TraitRef,TraitRefExt,Ty,
4848
TyExt,WhereClause,
4949
};
@@ -60,11 +60,18 @@ impl HirWrite for String {}
6060
implHirWritefor fmt::Formatter<'_>{}
6161

6262
pubstructHirFormatter<'a>{
63+
/// The database handle
6364
pubdb:&'adynHirDatabase,
65+
/// The sink to write into
6466
fmt:&'amutdynHirWrite,
67+
/// A buffer to intercept writes with, this allows us to track the overall size of the formatted output.
6568
buf:String,
69+
/// The current size of the formatted output.
6670
curr_size:usize,
67-
pub(crate)max_size:Option<usize>,
71+
/// Size from which we should truncate the output.
72+
max_size:Option<usize>,
73+
/// When rendering something that has a concept of "children" (like fields in a struct), this limits
74+
/// how many should be rendered.
6875
pubentity_limit:Option<usize>,
6976
omit_verbose_types:bool,
7077
closure_style:ClosureStyle,
@@ -304,7 +311,6 @@ impl DisplayTarget {
304311
#[derive(Debug)]
305312
pubenumDisplaySourceCodeError{
306313
PathNotFound,
307-
UnknownType,
308314
Coroutine,
309315
OpaqueType,
310316
}
@@ -418,6 +424,7 @@ impl HirDisplay for ProjectionTy {
418424
let proj_params = &self.substitution.as_slice(Interner)[..proj_params_count];
419425
if !proj_params.is_empty(){
420426
write!(f,"<")?;
427+
// FIXME use `hir_fmt_generics` here
421428
f.write_joined(proj_params,", ")?;
422429
write!(f,">")?;
423430
}
@@ -967,6 +974,7 @@ impl HirDisplay for Ty {
967974
.chain(fn_params)
968975
.flatten();
969976
write!(f,"<")?;
977+
// FIXME use `hir_fmt_generics` here
970978
f.write_joined(params,", ")?;
971979
write!(f,">")?;
972980
}
@@ -1037,6 +1045,7 @@ impl HirDisplay for Ty {
10371045
// FIXME: reconsider the generic args order upon formatting?
10381046
if parameters.len(Interner) > 0{
10391047
write!(f,"<")?;
1048+
// FIXME use `hir_fmt_generics` here
10401049
f.write_joined(parameters.as_slice(Interner),", ")?;
10411050
write!(f,">")?;
10421051
}
@@ -1287,11 +1296,10 @@ impl HirDisplay for Ty {
12871296
}
12881297
TyKind::Error => {
12891298
if f.display_target.is_source_code(){
1290-
returnErr(HirDisplayError::DisplaySourceCodeError(
1291-
DisplaySourceCodeError::UnknownType,
1292-
));
1299+
f.write_char('_')?;
1300+
}else{
1301+
write!(f,"{{unknown}}")?;
12931302
}
1294-
write!(f,"{{unknown}}")?;
12951303
}
12961304
TyKind::InferenceVar(..) => write!(f,"_")?,
12971305
TyKind::Coroutine(_, subst) => {
@@ -1331,98 +1339,90 @@ fn hir_fmt_generics(
13311339
parameters:&Substitution,
13321340
generic_def:Option<hir_def::GenericDefId>,
13331341
) -> Result<(),HirDisplayError>{
1334-
let db = f.db;
1335-
if parameters.len(Interner) > 0{
1336-
use std::cmp::Ordering;
1337-
let param_compare =
1338-
|a:&GenericArg,b:&GenericArg| match(a.data(Interner), b.data(Interner)){
1339-
(crate::GenericArgData::Lifetime(_),crate::GenericArgData::Lifetime(_)) => {
1340-
Ordering::Equal
1341-
}
1342-
(crate::GenericArgData::Lifetime(_), _) => Ordering::Less,
1343-
(_,crate::GenericArgData::Lifetime(_)) => Ordering::Less,
1344-
(_, _) => Ordering::Equal,
1345-
};
1346-
let parameters_to_write = if f.display_target.is_source_code() || f.omit_verbose_types(){
1347-
match generic_def
1348-
.map(|generic_def_id| db.generic_defaults(generic_def_id))
1349-
.filter(|defaults| !defaults.is_empty())
1350-
{
1351-
None => parameters.as_slice(Interner),
1352-
Some(default_parameters) => {
1353-
fnshould_show(
1354-
parameter:&GenericArg,
1355-
default_parameters:&[Binders<GenericArg>],
1356-
i:usize,
1357-
parameters:&Substitution,
1358-
) -> bool{
1359-
if parameter.ty(Interner).map(|it| it.kind(Interner))
1360-
== Some(&TyKind::Error)
1361-
{
1362-
returntrue;
1363-
}
1364-
ifletSome(ConstValue::Concrete(c)) =
1365-
parameter.constant(Interner).map(|it| &it.data(Interner).value)
1366-
{
1367-
if c.interned == ConstScalar::Unknown{
1368-
returntrue;
1369-
}
1370-
}
1371-
ifletSome(crate::LifetimeData::Static | crate::LifetimeData::Error) =
1372-
parameter.lifetime(Interner).map(|it| it.data(Interner))
1373-
{
1374-
returntrue;
1342+
if parameters.is_empty(Interner){
1343+
returnOk(());
1344+
}
1345+
1346+
let parameters_to_write =
1347+
generic_args_sans_defaults(f, generic_def, parameters.as_slice(Interner));
1348+
if !parameters_to_write.is_empty(){
1349+
write!(f,"<")?;
1350+
hir_fmt_generic_arguments(f, parameters_to_write)?;
1351+
write!(f,">")?;
1352+
}
1353+
1354+
Ok(())
1355+
}
1356+
1357+
fngeneric_args_sans_defaults<'ga>(
1358+
f:&mutHirFormatter<'_>,
1359+
generic_def:Option<hir_def::GenericDefId>,
1360+
parameters:&'ga[GenericArg],
1361+
) -> &'ga[GenericArg]{
1362+
if f.display_target.is_source_code() || f.omit_verbose_types(){
1363+
match generic_def
1364+
.map(|generic_def_id| f.db.generic_defaults(generic_def_id))
1365+
.filter(|it| !it.is_empty())
1366+
{
1367+
None => parameters,
1368+
Some(default_parameters) => {
1369+
let should_show = |arg:&GenericArg,i:usize| {
1370+
let is_err = |arg:&GenericArg| match arg.data(Interner){
1371+
chalk_ir::GenericArgData::Lifetime(it) => {
1372+
*it.data(Interner) == LifetimeData::Error
13751373
}
1376-
let default_parameter = match default_parameters.get(i){
1377-
Some(it) => it,
1378-
None => returntrue,
1379-
};
1380-
let actual_default =
1381-
default_parameter.clone().substitute(Interner,&parameters);
1382-
parameter != &actual_default
1374+
chalk_ir::GenericArgData::Ty(it) => *it.kind(Interner) == TyKind::Error,
1375+
chalk_ir::GenericArgData::Const(it) => matches!(
1376+
it.data(Interner).value,
1377+
ConstValue::Concrete(ConcreteConst{
1378+
interned:ConstScalar::Unknown,
1379+
..
1380+
})
1381+
),
1382+
};
1383+
// if the arg is error like, render it to inform the user
1384+
ifis_err(arg){
1385+
returntrue;
13831386
}
1384-
letmut default_from = 0;
1385-
for(i, parameter)in parameters.iter(Interner).enumerate(){
1386-
ifshould_show(parameter,&default_parameters, i, parameters){
1387-
default_from = i + 1;
1388-
}
1387+
// otherwise, if the arg is equal to the param default, hide it (unless the
1388+
// default is an error which can happen for the trait Self type)
1389+
default_parameters.get(i).is_none_or(|default_parameter| {
1390+
// !is_err(default_parameter.skip_binders())
1391+
// &&
1392+
arg != &default_parameter.clone().substitute(Interner,&parameters)
1393+
})
1394+
};
1395+
letmut default_from = 0;
1396+
for(i, parameter)in parameters.iter().enumerate(){
1397+
ifshould_show(parameter, i){
1398+
default_from = i + 1;
13891399
}
1390-
&parameters.as_slice(Interner)[0..default_from]
1391-
}
1392-
}
1393-
}else{
1394-
parameters.as_slice(Interner)
1395-
};
1396-
//FIXME: Should handle the ordering of lifetimes when creating substitutions
1397-
letmut parameters_to_write = parameters_to_write.to_vec();
1398-
parameters_to_write.sort_by(param_compare);
1399-
if !parameters_to_write.is_empty(){
1400-
write!(f,"<")?;
1401-
letmut first = true;
1402-
for generic_arg in parameters_to_write {
1403-
if !first {
1404-
write!(f,", ")?;
1405-
}
1406-
first = false;
1407-
if f.display_target.is_source_code(){
1408-
match generic_arg.data(Interner){
1409-
GenericArgData::Lifetime(l)
1410-
ifmatches!(l.data(Interner),LifetimeData::Error) =>
1411-
{
1412-
write!(f,"'_")
1413-
}
1414-
GenericArgData::Ty(t)ifmatches!(t.kind(Interner),TyKind::Error) => {
1415-
write!(f,"_")
1416-
}
1417-
_ => generic_arg.hir_fmt(f),
1418-
}?
1419-
}else{
1420-
generic_arg.hir_fmt(f)?;
14211400
}
1401+
&parameters[0..default_from]
14221402
}
1403+
}
1404+
}else{
1405+
parameters
1406+
}
1407+
}
14231408

1424-
write!(f,">")?;
1409+
fnhir_fmt_generic_arguments(
1410+
f:&mutHirFormatter<'_>,
1411+
parameters:&[GenericArg],
1412+
) -> Result<(),HirDisplayError>{
1413+
letmut first = true;
1414+
let lifetime_offset = parameters.iter().position(|arg| arg.lifetime(Interner).is_some());
1415+
1416+
let(ty_or_const, lifetimes) = match lifetime_offset {
1417+
Some(offset) => parameters.split_at(offset),
1418+
None => (parameters,&[][..]),
1419+
};
1420+
for generic_arg in lifetimes.iter().chain(ty_or_const){
1421+
if !first {
1422+
write!(f,", ")?;
14251423
}
1424+
first = false;
1425+
generic_arg.hir_fmt(f)?;
14261426
}
14271427
Ok(())
14281428
}
@@ -1544,20 +1544,29 @@ fn write_bounds_like_dyn_trait(
15441544
f.start_location_link(trait_.into());
15451545
write!(f,"{}", f.db.trait_data(trait_).name.display(f.db.upcast()))?;
15461546
f.end_location_link();
1547-
iflet[_, params @ ..] = trait_ref.substitution.as_slice(Interner){
1548-
ifis_fn_trait{
1547+
ifis_fn_trait{
1548+
iflet[_self, params @ ..] = trait_ref.substitution.as_slice(Interner){
15491549
ifletSome(args) =
15501550
params.first().and_then(|it| it.assert_ty_ref(Interner).as_tuple())
15511551
{
15521552
write!(f,"(")?;
1553-
f.write_joined(args.as_slice(Interner),", ")?;
1553+
hir_fmt_generic_arguments(f,args.as_slice(Interner))?;
15541554
write!(f,")")?;
15551555
}
1556-
}elseif !params.is_empty(){
1557-
write!(f,"<")?;
1558-
f.write_joined(params,", ")?;
1559-
// there might be assoc type bindings, so we leave the angle brackets open
1560-
angle_open = true;
1556+
}
1557+
}else{
1558+
let params = generic_args_sans_defaults(
1559+
f,
1560+
Some(trait_.into()),
1561+
trait_ref.substitution.as_slice(Interner),
1562+
);
1563+
iflet[_self, params @ ..] = params {
1564+
if !params.is_empty(){
1565+
write!(f,"<")?;
1566+
hir_fmt_generic_arguments(f, params)?;
1567+
// there might be assoc type bindings, so we leave the angle brackets open
1568+
angle_open = true;
1569+
}
15611570
}
15621571
}
15631572
}
@@ -1609,9 +1618,9 @@ fn write_bounds_like_dyn_trait(
16091618
let proj_arg_count = generics(f.db.upcast(), assoc_ty_id.into()).len_self();
16101619
if proj_arg_count > 0{
16111620
write!(f,"<")?;
1612-
f.write_joined(
1621+
hir_fmt_generic_arguments(
1622+
f,
16131623
&proj.substitution.as_slice(Interner)[..proj_arg_count],
1614-
", ",
16151624
)?;
16161625
write!(f,">")?;
16171626
}
@@ -1670,6 +1679,7 @@ fn fmt_trait_ref(
16701679
f.end_location_link();
16711680
if tr.substitution.len(Interner) > 1{
16721681
write!(f,"<")?;
1682+
// FIXME use `hir_fmt_generics` here
16731683
f.write_joined(&tr.substitution.as_slice(Interner)[1..],", ")?;
16741684
write!(f,">")?;
16751685
}
@@ -1728,15 +1738,16 @@ impl HirDisplay for Lifetime {
17281738
implHirDisplayforLifetimeData{
17291739
fnhir_fmt(&self,f:&mutHirFormatter<'_>) -> Result<(),HirDisplayError>{
17301740
matchself{
1731-
LifetimeData::BoundVar(idx) => idx.hir_fmt(f),
1732-
LifetimeData::InferenceVar(_) => write!(f,"_"),
17331741
LifetimeData::Placeholder(idx) => {
17341742
let id = lt_from_placeholder_idx(f.db,*idx);
17351743
let generics = generics(f.db.upcast(), id.parent);
17361744
let param_data = &generics.params[id.local_id];
17371745
write!(f,"{}", param_data.name.display(f.db.upcast()))?;
17381746
Ok(())
17391747
}
1748+
_ if f.display_target.is_source_code() => write!(f,"'_"),
1749+
LifetimeData::BoundVar(idx) => idx.hir_fmt(f),
1750+
LifetimeData::InferenceVar(_) => write!(f,"_"),
17401751
LifetimeData::Static => write!(f,"'static"),
17411752
LifetimeData::Error => write!(f,"'{{error}}"),
17421753
LifetimeData::Erased => Ok(()),

‎crates/hir-ty/src/lib.rs‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ use base_db::salsa::impl_intern_value_trivial;
5656
use chalk_ir::{
5757
fold::{Shift,TypeFoldable},
5858
interner::HasInterner,
59-
visit::{TypeSuperVisitable,TypeVisitable,TypeVisitor},
6059
NoSolution,
6160
};
6261
use either::Either;
@@ -98,7 +97,9 @@ pub use traits::TraitEnvironment;
9897
pubuse utils::{all_super_traits, is_fn_unsafe_to_call};
9998

10099
pubuse chalk_ir::{
101-
cast::Cast,AdtId,BoundVar,DebruijnIndex,Mutability,Safety,Scalar,TyVariableKind,
100+
cast::Cast,
101+
visit::{TypeSuperVisitable,TypeVisitable,TypeVisitor},
102+
AdtId,BoundVar,DebruijnIndex,Mutability,Safety,Scalar,TyVariableKind,
102103
};
103104

104105
pubtypeForeignDefId = chalk_ir::ForeignDefId<Interner>;

‎crates/hir-ty/src/tests/display_source_code.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ fn render_dyn_for_ty() {
8585
trait Foo<'a> {}
8686
8787
fn foo(foo: &dyn for<'a> Foo<'a>) {}
88-
// ^^^ &dyn Foo<'{error}>
88+
// ^^^ &dyn Foo<'_>
8989
"#,
9090
);
9191
}

‎crates/hir/src/lib.rs‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4711,10 +4711,12 @@ impl Type {
47114711
ifletWhereClause::Implemented(trait_ref) = pred.skip_binders(){
47124712
cb(type_.clone());
47134713
// skip the self type. it's likely the type we just got the bounds from
4714-
for ty in
4715-
trait_ref.substitution.iter(Interner).skip(1).filter_map(|a| a.ty(Interner))
4716-
{
4717-
walk_type(db,&type_.derived(ty.clone()), cb);
4714+
iflet[self_ty, params @ ..] = trait_ref.substitution.as_slice(Interner){
4715+
for ty in
4716+
params.iter().filter(|&ty| ty != self_ty).filter_map(|a| a.ty(Interner))
4717+
{
4718+
walk_type(db,&type_.derived(ty.clone()), cb);
4719+
}
47184720
}
47194721
}
47204722
}

0 commit comments

Comments
 (0)