Skip to content

Commit 421979b

Browse files
committed
HirDisplay prints ?Sized bounds now; impl Trait: Sized by default.
1 parent d9e6377 commit 421979b

File tree

5 files changed

+167
-14
lines changed

5 files changed

+167
-14
lines changed

crates/hir/src/display.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use hir_def::{
77
};
88
use hir_ty::display::{
99
write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError,
10-
HirFormatter,
10+
HirFormatter, SizedByDefault,
1111
};
1212
use hir_ty::Interner;
1313
use syntax::ast::{self, NameOwner};
@@ -239,7 +239,7 @@ impl HirDisplay for TypeParam {
239239
let predicates =
240240
bounds.iter().cloned().map(|b| b.substitute(&Interner, &substs)).collect::<Vec<_>>();
241241
if !(predicates.is_empty() || f.omit_verbose_types()) {
242-
write_bounds_like_dyn_trait_with_prefix(":", &predicates, f)?;
242+
write_bounds_like_dyn_trait_with_prefix(":", &predicates, SizedByDefault::Sized, f)?;
243243
}
244244
Ok(())
245245
}

crates/hir_ty/src/display.rs

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,12 @@ impl HirDisplay for Ty {
582582
.as_ref()
583583
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
584584
let bounds = data.substitute(&Interner, &parameters);
585-
write_bounds_like_dyn_trait_with_prefix("impl", bounds.skip_binders(), f)?;
585+
write_bounds_like_dyn_trait_with_prefix(
586+
"impl",
587+
bounds.skip_binders(),
588+
SizedByDefault::Sized,
589+
f,
590+
)?;
586591
// FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
587592
}
588593
ImplTraitId::AsyncBlockTypeImplTrait(..) => {
@@ -641,7 +646,12 @@ impl HirDisplay for Ty {
641646
_ => false,
642647
})
643648
.collect::<Vec<_>>();
644-
write_bounds_like_dyn_trait_with_prefix("impl", &bounds, f)?;
649+
write_bounds_like_dyn_trait_with_prefix(
650+
"impl",
651+
&bounds,
652+
SizedByDefault::Sized,
653+
f,
654+
)?;
645655
}
646656
}
647657
}
@@ -650,6 +660,7 @@ impl HirDisplay for Ty {
650660
write_bounds_like_dyn_trait_with_prefix(
651661
"dyn",
652662
dyn_ty.bounds.skip_binders().interned(),
663+
SizedByDefault::NotSized,
653664
f,
654665
)?;
655666
}
@@ -664,7 +675,12 @@ impl HirDisplay for Ty {
664675
.as_ref()
665676
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
666677
let bounds = data.substitute(&Interner, &opaque_ty.substitution);
667-
write_bounds_like_dyn_trait_with_prefix("impl", bounds.skip_binders(), f)?;
678+
write_bounds_like_dyn_trait_with_prefix(
679+
"impl",
680+
bounds.skip_binders(),
681+
SizedByDefault::Sized,
682+
f,
683+
)?;
668684
}
669685
ImplTraitId::AsyncBlockTypeImplTrait(..) => {
670686
write!(f, "{{async block}}")?;
@@ -713,22 +729,37 @@ fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = Trai
713729
utils::fn_traits(db, krate)
714730
}
715731

732+
fn is_sized_trait(db: &dyn DefDatabase, trait_: TraitId) -> Option<bool> {
733+
let krate = trait_.lookup(db).container.krate();
734+
let sized_trait =
735+
db.lang_item(krate, "sized".into()).and_then(|lang_item| lang_item.as_trait())?;
736+
Some(trait_ == sized_trait)
737+
}
738+
739+
#[derive(Clone, Copy, PartialEq, Eq)]
740+
pub enum SizedByDefault {
741+
NotSized,
742+
Sized,
743+
}
744+
716745
pub fn write_bounds_like_dyn_trait_with_prefix(
717746
prefix: &str,
718747
predicates: &[QuantifiedWhereClause],
748+
default_sized: SizedByDefault,
719749
f: &mut HirFormatter,
720750
) -> Result<(), HirDisplayError> {
721751
write!(f, "{}", prefix)?;
722752
if !predicates.is_empty() {
723753
write!(f, " ")?;
724-
write_bounds_like_dyn_trait(predicates, f)
754+
write_bounds_like_dyn_trait(predicates, default_sized, f)
725755
} else {
726756
Ok(())
727757
}
728758
}
729759

730760
fn write_bounds_like_dyn_trait(
731761
predicates: &[QuantifiedWhereClause],
762+
default_sized: SizedByDefault,
732763
f: &mut HirFormatter,
733764
) -> Result<(), HirDisplayError> {
734765
// Note: This code is written to produce nice results (i.e.
@@ -740,10 +771,22 @@ fn write_bounds_like_dyn_trait(
740771
let mut first = true;
741772
let mut angle_open = false;
742773
let mut is_fn_trait = false;
774+
let mut is_sized = None;
743775
for p in predicates.iter() {
744776
match p.skip_binders() {
745777
WhereClause::Implemented(trait_ref) => {
746778
let trait_ = trait_ref.hir_trait_id();
779+
match is_sized_trait(f.db.upcast(), trait_) {
780+
Some(true) => {
781+
is_sized = Some(true);
782+
if default_sized == SizedByDefault::Sized {
783+
// Don't print +Sized, but rather +?Sized if absent.
784+
continue;
785+
}
786+
}
787+
Some(false) => is_sized = is_sized.or(Some(false)),
788+
None => (),
789+
}
747790
if !is_fn_trait {
748791
is_fn_trait = fn_traits(f.db.upcast(), trait_).any(|it| it == trait_);
749792
}
@@ -808,6 +851,13 @@ fn write_bounds_like_dyn_trait(
808851
if angle_open {
809852
write!(f, ">")?;
810853
}
854+
if default_sized == SizedByDefault::Sized && is_sized.is_some() {
855+
if is_sized == Some(false) {
856+
write!(f, "{}?Sized", if first { "" } else { " + " })?;
857+
} else if first {
858+
write!(f, "Sized")?;
859+
}
860+
}
811861
Ok(())
812862
}
813863

crates/hir_ty/src/lower.rs

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,10 @@ impl<'a> TyLoweringContext<'a> {
226226
ImplTraitLoweringMode::Opaque => {
227227
let idx = self.impl_trait_counter.get();
228228
self.impl_trait_counter.set(idx + 1);
229+
let func = match self.resolver.generic_def() {
230+
Some(GenericDefId::FunctionId(f)) => f,
231+
_ => panic!("opaque impl trait lowering in non-function"),
232+
};
229233

230234
assert!(idx as usize == self.opaque_type_data.borrow().len());
231235
// this dance is to make sure the data is in the right
@@ -245,14 +249,10 @@ impl<'a> TyLoweringContext<'a> {
245249
// away instead of two.
246250
let actual_opaque_type_data = self
247251
.with_debruijn(DebruijnIndex::INNERMOST, |ctx| {
248-
ctx.lower_impl_trait(bounds)
252+
ctx.lower_impl_trait(bounds, func)
249253
});
250254
self.opaque_type_data.borrow_mut()[idx as usize] = actual_opaque_type_data;
251255

252-
let func = match self.resolver.generic_def() {
253-
Some(GenericDefId::FunctionId(f)) => f,
254-
_ => panic!("opaque impl trait lowering in non-function"),
255-
};
256256
let impl_trait_id = ImplTraitId::ReturnTypeImplTrait(func, idx);
257257
let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
258258
let generics = generics(self.db.upcast(), func.into());
@@ -871,13 +871,42 @@ impl<'a> TyLoweringContext<'a> {
871871
})
872872
}
873873

874-
fn lower_impl_trait(&self, bounds: &[Interned<TypeBound>]) -> ReturnTypeImplTrait {
874+
fn lower_impl_trait(
875+
&self,
876+
bounds: &[Interned<TypeBound>],
877+
func: FunctionId,
878+
) -> ReturnTypeImplTrait {
875879
cov_mark::hit!(lower_rpit);
876880
let self_ty =
877881
TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(&Interner);
882+
// XXX(iDawer): Can shifting mess with unsized_types? For now I better reinsure.
883+
let outer_unsized_types = self.unsized_types.replace(Default::default());
878884
let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
879-
bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)).collect()
885+
let mut predicates: Vec<_> = bounds
886+
.iter()
887+
.flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false))
888+
.collect();
889+
890+
if !ctx.unsized_types.borrow().contains(&self_ty) {
891+
let krate = func.lookup(ctx.db.upcast()).module(ctx.db.upcast()).krate();
892+
let sized_trait = ctx
893+
.db
894+
.lang_item(krate, "sized".into())
895+
.and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
896+
let sized_clause = sized_trait.map(|trait_id| {
897+
let clause = WhereClause::Implemented(TraitRef {
898+
trait_id,
899+
substitution: Substitution::from1(&Interner, self_ty.clone()),
900+
});
901+
crate::wrap_empty_binders(clause)
902+
});
903+
predicates.extend(sized_clause.into_iter());
904+
predicates.shrink_to_fit();
905+
}
906+
predicates
880907
});
908+
self.unsized_types.replace(outer_unsized_types);
909+
881910
ReturnTypeImplTrait { bounds: crate::make_only_type_binders(1, predicates) }
882911
}
883912
}

crates/hir_ty/src/tests/coercion.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ trait Foo {}
406406
fn test(f: impl Foo, g: &(impl Foo + ?Sized)) {
407407
let _: &dyn Foo = &f;
408408
let _: &dyn Foo = g;
409-
//^ expected &dyn Foo, got &impl Foo
409+
//^ expected &dyn Foo, got &impl Foo + ?Sized
410410
}
411411
"#,
412412
);

crates/hir_ty/src/tests/display_source_code.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,77 @@ fn foo(foo: &dyn for<'a> Foo<'a>) {}
6767
"#,
6868
);
6969
}
70+
71+
#[test]
72+
fn sized_bounds_apit() {
73+
check_types_source_code(
74+
r#"
75+
#[lang = "sized"]
76+
pub trait Sized {}
77+
78+
trait Foo {}
79+
trait Bar<T> {}
80+
struct S<T>;
81+
fn test(
82+
a: impl Foo,
83+
b: impl Foo + Sized,
84+
c: &(impl Foo + ?Sized),
85+
d: S<impl Foo>,
86+
e: impl Bar<impl Foo>,
87+
empty: impl,
88+
) {
89+
a;
90+
//^ impl Foo
91+
b;
92+
//^ impl Foo
93+
c;
94+
//^ &impl Foo + ?Sized
95+
d;
96+
//^ S<impl Foo>
97+
e;
98+
//^ impl Bar<impl Foo>
99+
empty;
100+
} //^ impl Sized
101+
"#,
102+
);
103+
}
104+
105+
#[test]
106+
fn sized_bounds_rpit() {
107+
check_types_source_code(
108+
r#"
109+
#[lang = "sized"]
110+
pub trait Sized {}
111+
112+
trait Foo {}
113+
fn foo() -> impl Foo { loop {} }
114+
fn test<T: Foo>() {
115+
let foo = foo();
116+
foo;
117+
} //^ impl Foo
118+
"#,
119+
);
120+
}
121+
122+
#[test]
123+
fn sized_bounds_impl_traits_in_fn_signature() {
124+
check_types_source_code(
125+
r#"
126+
#[lang = "sized"]
127+
pub trait Sized {}
128+
129+
trait Foo {}
130+
fn test(
131+
a: fn(impl Foo) -> impl Foo,
132+
b: fn(impl Foo + Sized) -> impl Foo + Sized,
133+
c: fn(&(impl Foo + ?Sized)) -> &(impl Foo + ?Sized),
134+
) {
135+
a;
136+
//^ fn(impl Foo) -> impl Foo
137+
b;
138+
//^ fn(impl Foo) -> impl Foo
139+
c;
140+
} //^ fn(&impl Foo + ?Sized) -> &impl Foo + ?Sized
141+
"#,
142+
);
143+
}

0 commit comments

Comments
 (0)