File tree Expand file tree Collapse file tree 4 files changed +45
-6
lines changed Expand file tree Collapse file tree 4 files changed +45
-6
lines changed Original file line number Diff line number Diff line change @@ -142,12 +142,21 @@ impl<T> Canonicalized<T> {
142
142
143
143
pub fn unify ( ty1 : & Canonical < Ty > , ty2 : & Canonical < Ty > ) -> Option < Substs > {
144
144
let mut table = InferenceTable :: new ( ) ;
145
+ let num_vars = ty1. num_vars . max ( ty2. num_vars ) ;
145
146
let vars =
146
- Substs :: builder ( ty1. num_vars ) . fill ( std:: iter:: repeat_with ( || table. new_type_var ( ) ) ) . build ( ) ;
147
- let ty_with_vars = ty1. value . clone ( ) . subst_bound_vars ( & vars) ;
148
- if !table. unify ( & ty_with_vars, & ty2. value ) {
147
+ Substs :: builder ( num_vars) . fill ( std:: iter:: repeat_with ( || table. new_type_var ( ) ) ) . build ( ) ;
148
+ let ty1_with_vars = ty1. value . clone ( ) . subst_bound_vars ( & vars) ;
149
+ let ty2_with_vars = ty2. value . clone ( ) . subst_bound_vars ( & vars) ;
150
+ if !table. unify ( & ty1_with_vars, & ty2_with_vars) {
149
151
return None ;
150
152
}
153
+ // default any type vars that weren't unified back to their original bound vars
154
+ // (kind of hacky)
155
+ for ( i, var) in vars. iter ( ) . enumerate ( ) {
156
+ if & * table. resolve_ty_shallow ( var) == var {
157
+ table. unify ( var, & Ty :: Bound ( i as u32 ) ) ;
158
+ }
159
+ }
151
160
Some (
152
161
Substs :: builder ( ty1. num_vars )
153
162
. fill ( vars. iter ( ) . map ( |v| table. resolve_ty_completely ( v. clone ( ) ) ) )
Original file line number Diff line number Diff line change @@ -355,6 +355,10 @@ impl Substs {
355
355
Substs ( self . 0 [ ..std:: cmp:: min ( self . 0 . len ( ) , n) ] . into ( ) )
356
356
}
357
357
358
+ pub fn suffix ( & self , n : usize ) -> Substs {
359
+ Substs ( self . 0 [ self . 0 . len ( ) - std:: cmp:: min ( self . 0 . len ( ) , n) ..] . into ( ) )
360
+ }
361
+
358
362
pub fn as_single ( & self ) -> & Ty {
359
363
if self . 0 . len ( ) != 1 {
360
364
panic ! ( "expected substs of len 1, got {:?}" , self ) ;
Original file line number Diff line number Diff line change @@ -508,10 +508,17 @@ pub(crate) fn inherent_impl_substs(
508
508
impl_id : ImplId ,
509
509
self_ty : & Canonical < Ty > ,
510
510
) -> Option < Substs > {
511
- let vars = Substs :: build_for_def ( db, impl_id) . fill_with_bound_vars ( 0 ) . build ( ) ;
511
+ // we create a var for each type parameter of the impl; we need to keep in
512
+ // mind here that `self_ty` might have vars of its own
513
+ let vars =
514
+ Substs :: build_for_def ( db, impl_id) . fill_with_bound_vars ( self_ty. num_vars as u32 ) . build ( ) ;
512
515
let self_ty_with_vars = db. impl_self_ty ( impl_id) . subst ( & vars) ;
513
- let self_ty_with_vars = Canonical { num_vars : vars. len ( ) , value : self_ty_with_vars } ;
514
- super :: infer:: unify ( & self_ty_with_vars, self_ty)
516
+ let self_ty_with_vars =
517
+ Canonical { num_vars : vars. len ( ) + self_ty. num_vars , value : self_ty_with_vars } ;
518
+ let substs = super :: infer:: unify ( & self_ty_with_vars, self_ty) ;
519
+ // we only want the substs for the vars we added, not the ones from self_ty
520
+ let result = substs. map ( |s| s. suffix ( vars. len ( ) ) ) ;
521
+ result
515
522
}
516
523
517
524
fn transform_receiver_ty (
Original file line number Diff line number Diff line change @@ -1048,6 +1048,25 @@ where
1048
1048
assert_eq ! ( t, "{unknown}" ) ;
1049
1049
}
1050
1050
1051
+ #[ test]
1052
+ fn method_resolution_3373 ( ) {
1053
+ let t = type_at (
1054
+ r#"
1055
+ //- /main.rs
1056
+ struct A<T>(T);
1057
+
1058
+ impl A<i32> {
1059
+ fn from(v: i32) -> A<i32> { A(v) }
1060
+ }
1061
+
1062
+ fn main() {
1063
+ A::from(3)<|>;
1064
+ }
1065
+ "# ,
1066
+ ) ;
1067
+ assert_eq ! ( t, "A<i32>" ) ;
1068
+ }
1069
+
1051
1070
#[ test]
1052
1071
fn method_resolution_slow ( ) {
1053
1072
// this can get quite slow if we set the solver size limit too high
You can’t perform that action at this time.
0 commit comments