Skip to content

Commit 443bc7f

Browse files
committed
Support layout of RPIT
1 parent 10891ef commit 443bc7f

File tree

8 files changed

+214
-65
lines changed

8 files changed

+214
-65
lines changed

crates/hir-ty/src/chalk_db.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
205205
.return_type_impl_traits(func)
206206
.expect("impl trait id without impl traits");
207207
let (datas, binders) = (*datas).as_ref().into_value_and_skipped_binders();
208-
let data = &datas.impl_traits[idx as usize];
208+
let data = &datas.impl_traits[idx];
209209
let bound = OpaqueTyDatumBound {
210210
bounds: make_single_type_binders(data.bounds.skip_binders().to_vec()),
211211
where_clauses: chalk_ir::Binders::empty(Interner, vec![]),

crates/hir-ty/src/chalk_ext.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -234,9 +234,8 @@ impl TyExt for Ty {
234234
}
235235
ImplTraitId::ReturnTypeImplTrait(func, idx) => {
236236
db.return_type_impl_traits(func).map(|it| {
237-
let data = (*it)
238-
.as_ref()
239-
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
237+
let data =
238+
(*it).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
240239
data.substitute(Interner, &subst).into_value_and_skipped_binders().0
241240
})
242241
}
@@ -247,9 +246,8 @@ impl TyExt for Ty {
247246
{
248247
ImplTraitId::ReturnTypeImplTrait(func, idx) => {
249248
db.return_type_impl_traits(func).map(|it| {
250-
let data = (*it)
251-
.as_ref()
252-
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
249+
let data =
250+
(*it).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
253251
data.substitute(Interner, &opaque_ty.substitution)
254252
})
255253
}

crates/hir-ty/src/display.rs

+6-9
Original file line numberDiff line numberDiff line change
@@ -458,9 +458,8 @@ impl HirDisplay for Ty {
458458
let datas = db
459459
.return_type_impl_traits(func)
460460
.expect("impl trait id without data");
461-
let data = (*datas)
462-
.as_ref()
463-
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
461+
let data =
462+
(*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
464463
let bounds = data.substitute(Interner, parameters);
465464
let mut len = bounds.skip_binders().len();
466465

@@ -718,9 +717,8 @@ impl HirDisplay for Ty {
718717
ImplTraitId::ReturnTypeImplTrait(func, idx) => {
719718
let datas =
720719
db.return_type_impl_traits(func).expect("impl trait id without data");
721-
let data = (*datas)
722-
.as_ref()
723-
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
720+
let data =
721+
(*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
724722
let bounds = data.substitute(Interner, &parameters);
725723
let krate = func.lookup(db.upcast()).module(db.upcast()).krate();
726724
write_bounds_like_dyn_trait_with_prefix(
@@ -828,9 +826,8 @@ impl HirDisplay for Ty {
828826
ImplTraitId::ReturnTypeImplTrait(func, idx) => {
829827
let datas =
830828
db.return_type_impl_traits(func).expect("impl trait id without data");
831-
let data = (*datas)
832-
.as_ref()
833-
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
829+
let data =
830+
(*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
834831
let bounds = data.substitute(Interner, &opaque_ty.substitution);
835832
let krate = func.lookup(db.upcast()).module(db.upcast()).krate();
836833
write_bounds_like_dyn_trait_with_prefix(

crates/hir-ty/src/infer.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ use stdx::always;
3939
use crate::{
4040
db::HirDatabase, fold_tys, fold_tys_and_consts, infer::coerce::CoerceMany,
4141
lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Const, DomainGoal,
42-
GenericArg, Goal, ImplTraitId, InEnvironment, Interner, ProjectionTy, Substitution,
42+
GenericArg, Goal, ImplTraitId, InEnvironment, Interner, ProjectionTy, RpitId, Substitution,
4343
TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
4444
};
4545

@@ -352,6 +352,7 @@ pub struct InferenceResult {
352352
/// **Note**: When a pattern type is resolved it may still contain
353353
/// unresolved or missing subpatterns or subpatterns of mismatched types.
354354
pub type_of_pat: ArenaMap<PatId, Ty>,
355+
pub type_of_rpit: ArenaMap<RpitId, Ty>,
355356
type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>,
356357
/// Interned common types to return references to.
357358
standard_types: InternedStandardTypes,
@@ -525,6 +526,9 @@ impl<'a> InferenceContext<'a> {
525526
for ty in result.type_of_pat.values_mut() {
526527
*ty = table.resolve_completely(ty.clone());
527528
}
529+
for ty in result.type_of_rpit.iter_mut().map(|x| x.1) {
530+
*ty = table.resolve_completely(ty.clone());
531+
}
528532
for mismatch in result.type_mismatches.values_mut() {
529533
mismatch.expected = table.resolve_completely(mismatch.expected.clone());
530534
mismatch.actual = table.resolve_completely(mismatch.actual.clone());
@@ -603,7 +607,7 @@ impl<'a> InferenceContext<'a> {
603607
_ => unreachable!(),
604608
};
605609
let bounds = (*rpits).map_ref(|rpits| {
606-
rpits.impl_traits[idx as usize].bounds.map_ref(|it| it.into_iter())
610+
rpits.impl_traits[idx].bounds.map_ref(|it| it.into_iter())
607611
});
608612
let var = self.table.new_type_var();
609613
let var_subst = Substitution::from1(Interner, var.clone());
@@ -616,6 +620,7 @@ impl<'a> InferenceContext<'a> {
616620
always!(binders.is_empty(Interner)); // quantified where clauses not yet handled
617621
self.push_obligation(var_predicate.cast(Interner));
618622
}
623+
self.result.type_of_rpit.insert(idx, var.clone());
619624
var
620625
},
621626
DebruijnIndex::INNERMOST,

crates/hir-ty/src/layout.rs

+15-4
Original file line numberDiff line numberDiff line change
@@ -225,10 +225,21 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Lay
225225
ptr.valid_range_mut().start = 1;
226226
Layout::scalar(dl, ptr)
227227
}
228-
TyKind::Closure(_, _)
229-
| TyKind::OpaqueType(_, _)
230-
| TyKind::Generator(_, _)
231-
| TyKind::GeneratorWitness(_, _) => return Err(LayoutError::NotImplemented),
228+
TyKind::OpaqueType(opaque_ty_id, _) => {
229+
let impl_trait_id = db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
230+
match impl_trait_id {
231+
crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => {
232+
let infer = db.infer(func.into());
233+
layout_of_ty(db, &infer.type_of_rpit[idx], krate)?
234+
}
235+
crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => {
236+
return Err(LayoutError::NotImplemented)
237+
}
238+
}
239+
}
240+
TyKind::Closure(_, _) | TyKind::Generator(_, _) | TyKind::GeneratorWitness(_, _) => {
241+
return Err(LayoutError::NotImplemented)
242+
}
232243
TyKind::AssociatedType(_, _)
233244
| TyKind::Error
234245
| TyKind::Alias(_)

crates/hir-ty/src/layout/tests.rs

+106-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use hir_def::{
55
layout::{Layout, LayoutError},
66
};
77

8-
use crate::{test_db::TestDB, Interner, Substitution};
8+
use crate::{db::HirDatabase, test_db::TestDB, Interner, Substitution};
99

1010
use super::layout_of_ty;
1111

@@ -45,13 +45,64 @@ fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Layout, LayoutError> {
4545
layout_of_ty(&db, &goal_ty, module_id.krate())
4646
}
4747

48+
/// A version of `eval_goal` for types that can not be expressed in ADTs, like closures and `impl Trait`
49+
fn eval_expr(ra_fixture: &str, minicore: &str) -> Result<Layout, LayoutError> {
50+
// using unstable cargo features failed, fall back to using plain rustc
51+
let mut cmd = std::process::Command::new("rustc");
52+
cmd.args(["-Z", "unstable-options", "--print", "target-spec-json"]).env("RUSTC_BOOTSTRAP", "1");
53+
let output = cmd.output().unwrap();
54+
assert!(output.status.success(), "{}", output.status);
55+
let stdout = String::from_utf8(output.stdout).unwrap();
56+
let target_data_layout =
57+
stdout.split_once(r#""data-layout": ""#).unwrap().1.split_once('"').unwrap().0.to_owned();
58+
59+
let ra_fixture = format!(
60+
"{minicore}//- /main.rs crate:test target_data_layout:{target_data_layout}\nfn main(){{let goal = {{{ra_fixture}}};}}",
61+
);
62+
63+
let (db, file_id) = TestDB::with_single_file(&ra_fixture);
64+
let module_id = db.module_for_file(file_id);
65+
let def_map = module_id.def_map(&db);
66+
let scope = &def_map[module_id.local_id].scope;
67+
let adt_id = scope
68+
.declarations()
69+
.find_map(|x| match x {
70+
hir_def::ModuleDefId::FunctionId(x) => {
71+
let name = db.function_data(x).name.to_smol_str();
72+
(name == "main").then_some(x)
73+
}
74+
_ => None,
75+
})
76+
.unwrap();
77+
let hir_body = db.body(adt_id.into());
78+
let pat = hir_body
79+
.pats
80+
.iter()
81+
.find(|x| match x.1 {
82+
hir_def::expr::Pat::Bind { name, .. } => name.to_smol_str() == "goal",
83+
_ => false,
84+
})
85+
.unwrap()
86+
.0;
87+
let infer = db.infer(adt_id.into());
88+
let goal_ty = infer.type_of_pat[pat].clone();
89+
layout_of_ty(&db, &goal_ty, module_id.krate())
90+
}
91+
4892
#[track_caller]
4993
fn check_size_and_align(ra_fixture: &str, minicore: &str, size: u64, align: u64) {
5094
let l = eval_goal(ra_fixture, minicore).unwrap();
5195
assert_eq!(l.size.bytes(), size);
5296
assert_eq!(l.align.abi.bytes(), align);
5397
}
5498

99+
#[track_caller]
100+
fn check_size_and_align_expr(ra_fixture: &str, minicore: &str, size: u64, align: u64) {
101+
let l = eval_expr(ra_fixture, minicore).unwrap();
102+
assert_eq!(l.size.bytes(), size);
103+
assert_eq!(l.align.abi.bytes(), align);
104+
}
105+
55106
#[track_caller]
56107
fn check_fail(ra_fixture: &str, e: LayoutError) {
57108
let r = eval_goal(ra_fixture, "");
@@ -85,11 +136,31 @@ macro_rules! size_and_align {
85136
};
86137
}
87138

139+
macro_rules! size_and_align_expr {
140+
($($t:tt)*) => {
141+
{
142+
#[allow(dead_code)]
143+
{
144+
let val = { $($t)* };
145+
check_size_and_align_expr(
146+
stringify!($($t)*),
147+
"",
148+
::std::mem::size_of_val(&val) as u64,
149+
::std::mem::align_of_val(&val) as u64,
150+
);
151+
}
152+
}
153+
};
154+
}
155+
88156
#[test]
89157
fn hello_world() {
90158
size_and_align! {
91159
struct Goal(i32);
92160
}
161+
size_and_align_expr! {
162+
2i32
163+
}
93164
}
94165

95166
#[test]
@@ -143,6 +214,40 @@ fn generic() {
143214
}
144215
}
145216

217+
#[test]
218+
fn return_position_impl_trait() {
219+
size_and_align_expr! {
220+
trait T {}
221+
impl T for i32 {}
222+
impl T for i64 {}
223+
fn foo() -> impl T { 2i64 }
224+
foo()
225+
}
226+
size_and_align_expr! {
227+
trait T {}
228+
impl T for i32 {}
229+
impl T for i64 {}
230+
fn foo() -> (impl T, impl T, impl T) { (2i64, 5i32, 7i32) }
231+
foo()
232+
}
233+
size_and_align_expr! {
234+
struct Foo<T>(T, T, (T, T));
235+
trait T {}
236+
impl T for Foo<i32> {}
237+
impl T for Foo<i64> {}
238+
239+
fn foo() -> Foo<impl T> { Foo(
240+
Foo(1i64, 2, (3, 4)),
241+
Foo(5, 6, (7, 8)),
242+
(
243+
Foo(1i64, 2, (3, 4)),
244+
Foo(5, 6, (7, 8)),
245+
),
246+
) }
247+
foo()
248+
}
249+
}
250+
146251
#[test]
147252
fn enums() {
148253
size_and_align! {

crates/hir-ty/src/lib.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ use chalk_ir::{
4545
use hir_def::{expr::ExprId, type_ref::Rawness, TypeOrConstParamId};
4646
use hir_expand::name;
4747
use itertools::Either;
48+
use la_arena::{Arena, Idx};
4849
use rustc_hash::FxHashSet;
4950
use traits::FnTrait;
5051
use utils::Generics;
@@ -290,22 +291,24 @@ impl TypeFoldable<Interner> for CallableSig {
290291

291292
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
292293
pub enum ImplTraitId {
293-
ReturnTypeImplTrait(hir_def::FunctionId, u16),
294+
ReturnTypeImplTrait(hir_def::FunctionId, RpitId),
294295
AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId),
295296
}
296297

297298
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
298299
pub struct ReturnTypeImplTraits {
299-
pub(crate) impl_traits: Vec<ReturnTypeImplTrait>,
300+
pub(crate) impl_traits: Arena<ReturnTypeImplTrait>,
300301
}
301302

302303
has_interner!(ReturnTypeImplTraits);
303304

304305
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
305-
pub(crate) struct ReturnTypeImplTrait {
306+
pub struct ReturnTypeImplTrait {
306307
pub(crate) bounds: Binders<Vec<QuantifiedWhereClause>>,
307308
}
308309

310+
pub type RpitId = Idx<ReturnTypeImplTrait>;
311+
309312
pub fn static_lifetime() -> Lifetime {
310313
LifetimeData::Static.intern(Interner)
311314
}

0 commit comments

Comments
 (0)