Skip to content

Commit a609336

Browse files
Merge #4765
4765: Fix type parameter defaults r=matklad a=flodiebold They should not be applied in expression or pattern contexts, unless there are other explicitly given type args. (The existing tests about this were actually wrong.) Co-authored-by: Florian Diebold <florian.diebold@freiheit.com>
2 parents 02f7b5d + a4a4a18 commit a609336

File tree

10 files changed

+192
-115
lines changed

10 files changed

+192
-115
lines changed

crates/ra_assists/src/handlers/add_explicit_type.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ struct Test<K, T = u8> {
195195
}
196196
197197
fn main() {
198-
let test<|> = Test { t: 23, k: 33 };
198+
let test<|> = Test { t: 23u8, k: 33 };
199199
}"#,
200200
r#"
201201
struct Test<K, T = u8> {
@@ -204,7 +204,7 @@ struct Test<K, T = u8> {
204204
}
205205
206206
fn main() {
207-
let test: Test<i32> = Test { t: 23, k: 33 };
207+
let test: Test<i32> = Test { t: 23u8, k: 33 };
208208
}"#,
209209
);
210210
}

crates/ra_hir_ty/src/infer.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -439,13 +439,13 @@ impl<'a> InferenceContext<'a> {
439439
};
440440
return match resolution {
441441
TypeNs::AdtId(AdtId::StructId(strukt)) => {
442-
let substs = Ty::substs_from_path(&ctx, path, strukt.into());
442+
let substs = Ty::substs_from_path(&ctx, path, strukt.into(), true);
443443
let ty = self.db.ty(strukt.into());
444444
let ty = self.insert_type_vars(ty.subst(&substs));
445445
forbid_unresolved_segments((ty, Some(strukt.into())), unresolved)
446446
}
447447
TypeNs::EnumVariantId(var) => {
448-
let substs = Ty::substs_from_path(&ctx, path, var.into());
448+
let substs = Ty::substs_from_path(&ctx, path, var.into(), true);
449449
let ty = self.db.ty(var.parent.into());
450450
let ty = self.insert_type_vars(ty.subst(&substs));
451451
forbid_unresolved_segments((ty, Some(var.into())), unresolved)

crates/ra_hir_ty/src/infer/path.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ impl<'a> InferenceContext<'a> {
9595
// self_subst is just for the parent
9696
let parent_substs = self_subst.unwrap_or_else(Substs::empty);
9797
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
98-
let substs = Ty::substs_from_path(&ctx, path, typable);
98+
let substs = Ty::substs_from_path(&ctx, path, typable, true);
9999
let full_substs = Substs::builder(substs.len())
100100
.use_parent_substs(&parent_substs)
101101
.fill(substs.0[parent_substs.len()..].iter().cloned())
@@ -141,6 +141,7 @@ impl<'a> InferenceContext<'a> {
141141
def,
142142
resolved_segment,
143143
remaining_segments_for_ty,
144+
true,
144145
);
145146
if let Ty::Unknown = ty {
146147
return None;

crates/ra_hir_ty/src/lower.rs

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ impl Ty {
323323
resolution: TypeNs,
324324
resolved_segment: PathSegment<'_>,
325325
remaining_segments: PathSegments<'_>,
326+
infer_args: bool,
326327
) -> (Ty, Option<TypeNs>) {
327328
let ty = match resolution {
328329
TypeNs::TraitId(trait_) => {
@@ -400,9 +401,15 @@ impl Ty {
400401
ctx.db.ty(adt.into()).subst(&substs)
401402
}
402403

403-
TypeNs::AdtId(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()),
404-
TypeNs::BuiltinType(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()),
405-
TypeNs::TypeAliasId(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()),
404+
TypeNs::AdtId(it) => {
405+
Ty::from_hir_path_inner(ctx, resolved_segment, it.into(), infer_args)
406+
}
407+
TypeNs::BuiltinType(it) => {
408+
Ty::from_hir_path_inner(ctx, resolved_segment, it.into(), infer_args)
409+
}
410+
TypeNs::TypeAliasId(it) => {
411+
Ty::from_hir_path_inner(ctx, resolved_segment, it.into(), infer_args)
412+
}
406413
// FIXME: report error
407414
TypeNs::EnumVariantId(_) => return (Ty::Unknown, None),
408415
};
@@ -428,7 +435,13 @@ impl Ty {
428435
),
429436
Some(i) => (path.segments().get(i - 1).unwrap(), path.segments().skip(i)),
430437
};
431-
Ty::from_partly_resolved_hir_path(ctx, resolution, resolved_segment, remaining_segments)
438+
Ty::from_partly_resolved_hir_path(
439+
ctx,
440+
resolution,
441+
resolved_segment,
442+
remaining_segments,
443+
false,
444+
)
432445
}
433446

434447
fn select_associated_type(
@@ -474,13 +487,14 @@ impl Ty {
474487
ctx: &TyLoweringContext<'_>,
475488
segment: PathSegment<'_>,
476489
typable: TyDefId,
490+
infer_args: bool,
477491
) -> Ty {
478492
let generic_def = match typable {
479493
TyDefId::BuiltinType(_) => None,
480494
TyDefId::AdtId(it) => Some(it.into()),
481495
TyDefId::TypeAliasId(it) => Some(it.into()),
482496
};
483-
let substs = substs_from_path_segment(ctx, segment, generic_def, false);
497+
let substs = substs_from_path_segment(ctx, segment, generic_def, infer_args);
484498
ctx.db.ty(typable).subst(&substs)
485499
}
486500

@@ -493,6 +507,7 @@ impl Ty {
493507
// `ValueTyDefId` is just a convenient way to pass generics and
494508
// special-case enum variants
495509
resolved: ValueTyDefId,
510+
infer_args: bool,
496511
) -> Substs {
497512
let last = path.segments().last().expect("path should have at least one segment");
498513
let (segment, generic_def) = match resolved {
@@ -515,22 +530,27 @@ impl Ty {
515530
(segment, Some(var.parent.into()))
516531
}
517532
};
518-
substs_from_path_segment(ctx, segment, generic_def, false)
533+
substs_from_path_segment(ctx, segment, generic_def, infer_args)
519534
}
520535
}
521536

522-
pub(super) fn substs_from_path_segment(
537+
fn substs_from_path_segment(
523538
ctx: &TyLoweringContext<'_>,
524539
segment: PathSegment<'_>,
525540
def_generic: Option<GenericDefId>,
526-
_add_self_param: bool,
541+
infer_args: bool,
527542
) -> Substs {
528543
let mut substs = Vec::new();
529544
let def_generics = def_generic.map(|def| generics(ctx.db.upcast(), def));
530545

531546
let (parent_params, self_params, type_params, impl_trait_params) =
532547
def_generics.map_or((0, 0, 0, 0), |g| g.provenance_split());
548+
let total_len = parent_params + self_params + type_params + impl_trait_params;
549+
533550
substs.extend(iter::repeat(Ty::Unknown).take(parent_params));
551+
552+
let mut had_explicit_args = false;
553+
534554
if let Some(generic_args) = &segment.args_and_bindings {
535555
if !generic_args.has_self_type {
536556
substs.extend(iter::repeat(Ty::Unknown).take(self_params));
@@ -542,31 +562,35 @@ pub(super) fn substs_from_path_segment(
542562
for arg in generic_args.args.iter().skip(skip).take(expected_num) {
543563
match arg {
544564
GenericArg::Type(type_ref) => {
565+
had_explicit_args = true;
545566
let ty = Ty::from_hir(ctx, type_ref);
546567
substs.push(ty);
547568
}
548569
}
549570
}
550571
}
551-
let total_len = parent_params + self_params + type_params + impl_trait_params;
552-
// add placeholders for args that were not provided
553-
for _ in substs.len()..total_len {
554-
substs.push(Ty::Unknown);
555-
}
556-
assert_eq!(substs.len(), total_len);
557572

558-
// handle defaults
559-
if let Some(def_generic) = def_generic {
560-
let default_substs = ctx.db.generic_defaults(def_generic);
561-
assert_eq!(substs.len(), default_substs.len());
573+
// handle defaults. In expression or pattern path segments without
574+
// explicitly specified type arguments, missing type arguments are inferred
575+
// (i.e. defaults aren't used).
576+
if !infer_args || had_explicit_args {
577+
if let Some(def_generic) = def_generic {
578+
let default_substs = ctx.db.generic_defaults(def_generic);
579+
assert_eq!(total_len, default_substs.len());
562580

563-
for (i, default_ty) in default_substs.iter().enumerate() {
564-
if substs[i] == Ty::Unknown {
565-
substs[i] = default_ty.clone();
581+
for default_ty in default_substs.iter().skip(substs.len()) {
582+
substs.push(default_ty.clone());
566583
}
567584
}
568585
}
569586

587+
// add placeholders for args that were not provided
588+
// FIXME: emit diagnostics in contexts where this is not allowed
589+
for _ in substs.len()..total_len {
590+
substs.push(Ty::Unknown);
591+
}
592+
assert_eq!(substs.len(), total_len);
593+
570594
Substs(substs.into())
571595
}
572596

@@ -615,9 +639,7 @@ impl TraitRef {
615639
segment: PathSegment<'_>,
616640
resolved: TraitId,
617641
) -> Substs {
618-
let has_self_param =
619-
segment.args_and_bindings.as_ref().map(|a| a.has_self_type).unwrap_or(false);
620-
substs_from_path_segment(ctx, segment, Some(resolved.into()), !has_self_param)
642+
substs_from_path_segment(ctx, segment, Some(resolved.into()), false)
621643
}
622644

623645
pub(crate) fn from_type_bound(

crates/ra_hir_ty/src/tests/display_source_code.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ fn omit_default_type_parameters() {
2929
//- /main.rs
3030
struct Foo<T = u8> { t: T }
3131
fn main() {
32-
let foo = Foo { t: 5 };
32+
let foo = Foo { t: 5u8 };
3333
foo<|>;
3434
}
3535
",
@@ -41,7 +41,7 @@ fn omit_default_type_parameters() {
4141
//- /main.rs
4242
struct Foo<K, T = u8> { k: K, t: T }
4343
fn main() {
44-
let foo = Foo { k: 400, t: 5 };
44+
let foo = Foo { k: 400, t: 5u8 };
4545
foo<|>;
4646
}
4747
",

crates/ra_hir_ty/src/tests/method_resolution.rs

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -183,60 +183,6 @@ fn test() {
183183
);
184184
}
185185

186-
#[test]
187-
fn infer_associated_method_generics_with_default_param() {
188-
assert_snapshot!(
189-
infer(r#"
190-
struct Gen<T=u32> {
191-
val: T
192-
}
193-
194-
impl<T> Gen<T> {
195-
pub fn make() -> Gen<T> {
196-
loop { }
197-
}
198-
}
199-
200-
fn test() {
201-
let a = Gen::make();
202-
}
203-
"#),
204-
@r###"
205-
80..104 '{ ... }': Gen<T>
206-
90..98 'loop { }': !
207-
95..98 '{ }': ()
208-
118..146 '{ ...e(); }': ()
209-
128..129 'a': Gen<u32>
210-
132..141 'Gen::make': fn make<u32>() -> Gen<u32>
211-
132..143 'Gen::make()': Gen<u32>
212-
"###
213-
);
214-
}
215-
216-
#[test]
217-
fn infer_associated_method_generics_with_default_tuple_param() {
218-
let t = type_at(
219-
r#"
220-
//- /main.rs
221-
struct Gen<T=()> {
222-
val: T
223-
}
224-
225-
impl<T> Gen<T> {
226-
pub fn make() -> Gen<T> {
227-
loop { }
228-
}
229-
}
230-
231-
fn test() {
232-
let a = Gen::make();
233-
a.val<|>;
234-
}
235-
"#,
236-
);
237-
assert_eq!(t, "()");
238-
}
239-
240186
#[test]
241187
fn infer_associated_method_generics_without_args() {
242188
assert_snapshot!(

crates/ra_hir_ty/src/tests/simple.rs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1997,3 +1997,111 @@ fn foo() {
19971997
"###
19981998
);
19991999
}
2000+
2001+
#[test]
2002+
fn generic_default() {
2003+
assert_snapshot!(
2004+
infer(r#"
2005+
struct Thing<T = ()> { t: T }
2006+
enum OtherThing<T = ()> {
2007+
One { t: T },
2008+
Two(T),
2009+
}
2010+
2011+
fn test(t1: Thing, t2: OtherThing, t3: Thing<i32>, t4: OtherThing<i32>) {
2012+
t1.t;
2013+
t3.t;
2014+
match t2 {
2015+
OtherThing::One { t } => { t; },
2016+
OtherThing::Two(t) => { t; },
2017+
}
2018+
match t4 {
2019+
OtherThing::One { t } => { t; },
2020+
OtherThing::Two(t) => { t; },
2021+
}
2022+
}
2023+
"#),
2024+
@r###"
2025+
98..100 't1': Thing<()>
2026+
109..111 't2': OtherThing<()>
2027+
125..127 't3': Thing<i32>
2028+
141..143 't4': OtherThing<i32>
2029+
162..385 '{ ... } }': ()
2030+
168..170 't1': Thing<()>
2031+
168..172 't1.t': ()
2032+
178..180 't3': Thing<i32>
2033+
178..182 't3.t': i32
2034+
188..283 'match ... }': ()
2035+
194..196 't2': OtherThing<()>
2036+
207..228 'OtherT... { t }': OtherThing<()>
2037+
225..226 't': ()
2038+
232..238 '{ t; }': ()
2039+
234..235 't': ()
2040+
248..266 'OtherT...Two(t)': OtherThing<()>
2041+
264..265 't': ()
2042+
270..276 '{ t; }': ()
2043+
272..273 't': ()
2044+
288..383 'match ... }': ()
2045+
294..296 't4': OtherThing<i32>
2046+
307..328 'OtherT... { t }': OtherThing<i32>
2047+
325..326 't': i32
2048+
332..338 '{ t; }': ()
2049+
334..335 't': i32
2050+
348..366 'OtherT...Two(t)': OtherThing<i32>
2051+
364..365 't': i32
2052+
370..376 '{ t; }': ()
2053+
372..373 't': i32
2054+
"###
2055+
);
2056+
}
2057+
2058+
#[test]
2059+
fn generic_default_in_struct_literal() {
2060+
assert_snapshot!(
2061+
infer(r#"
2062+
struct Thing<T = ()> { t: T }
2063+
enum OtherThing<T = ()> {
2064+
One { t: T },
2065+
Two(T),
2066+
}
2067+
2068+
fn test() {
2069+
let x = Thing { t: loop {} };
2070+
let y = Thing { t: () };
2071+
let z = Thing { t: 1i32 };
2072+
if let Thing { t } = z {
2073+
t;
2074+
}
2075+
2076+
let a = OtherThing::One { t: 1i32 };
2077+
let b = OtherThing::Two(1i32);
2078+
}
2079+
"#),
2080+
@r###"
2081+
100..320 '{ ...32); }': ()
2082+
110..111 'x': Thing<!>
2083+
114..134 'Thing ...p {} }': Thing<!>
2084+
125..132 'loop {}': !
2085+
130..132 '{}': ()
2086+
144..145 'y': Thing<()>
2087+
148..163 'Thing { t: () }': Thing<()>
2088+
159..161 '()': ()
2089+
173..174 'z': Thing<i32>
2090+
177..194 'Thing ...1i32 }': Thing<i32>
2091+
188..192 '1i32': i32
2092+
200..241 'if let... }': ()
2093+
207..218 'Thing { t }': Thing<i32>
2094+
215..216 't': i32
2095+
221..222 'z': Thing<i32>
2096+
223..241 '{ ... }': ()
2097+
233..234 't': i32
2098+
251..252 'a': OtherThing<i32>
2099+
255..282 'OtherT...1i32 }': OtherThing<i32>
2100+
276..280 '1i32': i32
2101+
292..293 'b': OtherThing<i32>
2102+
296..311 'OtherThing::Two': Two<i32>(i32) -> OtherThing<i32>
2103+
296..317 'OtherT...(1i32)': OtherThing<i32>
2104+
312..316 '1i32': i32
2105+
"###
2106+
);
2107+
}

0 commit comments

Comments
 (0)