@@ -17,7 +17,7 @@ use rustc_smir::rustc_internal;
17
17
use stable_mir:: mir:: mono:: Instance ;
18
18
use stable_mir:: mir:: visit:: { Location , MirVisitor } ;
19
19
use stable_mir:: mir:: Constant ;
20
- use stable_mir:: ty:: FnDef ;
20
+ use stable_mir:: ty:: { FnDef , RigidTy , TyKind } ;
21
21
use stable_mir:: { CrateDef , CrateItem } ;
22
22
23
23
use self :: annotations:: update_stub_mapping;
@@ -37,6 +37,24 @@ pub fn harness_stub_map(
37
37
stub_pairs
38
38
}
39
39
40
+ /// Retrieve the index of the host parameter if old definition has one, but not the new definition.
41
+ ///
42
+ /// This is to allow constant functions to be stubbed by non-constant functions when the
43
+ /// `effect` feature is on.
44
+ ///
45
+ /// Note that the opposite is not supported today, but users should be able to change their stubs.
46
+ ///
47
+ /// Note that this has no effect at runtime.
48
+ pub fn contract_host_param ( tcx : TyCtxt , old_def : FnDef , new_def : FnDef ) -> Option < usize > {
49
+ let old_generics = tcx. generics_of ( rustc_internal:: internal ( tcx, old_def. def_id ( ) ) ) ;
50
+ let new_generics = tcx. generics_of ( rustc_internal:: internal ( tcx, new_def. def_id ( ) ) ) ;
51
+ if old_generics. host_effect_index . is_some ( ) && new_generics. host_effect_index . is_none ( ) {
52
+ old_generics. host_effect_index
53
+ } else {
54
+ None
55
+ }
56
+ }
57
+
40
58
/// Checks whether the stub is compatible with the original function/method: do
41
59
/// the arities and types (of the parameters and return values) match up? This
42
60
/// does **NOT** check whether the type variables are constrained to implement
@@ -61,15 +79,26 @@ pub fn check_compatibility(tcx: TyCtxt, old_def: FnDef, new_def: FnDef) -> Resul
61
79
// Check whether the numbers of generic parameters match.
62
80
let old_def_id = rustc_internal:: internal ( tcx, old_def. def_id ( ) ) ;
63
81
let new_def_id = rustc_internal:: internal ( tcx, new_def. def_id ( ) ) ;
64
- let old_num_generics = tcx. generics_of ( old_def_id) . count ( ) ;
65
- let stub_num_generics = tcx. generics_of ( new_def_id) . count ( ) ;
66
- if old_num_generics != stub_num_generics {
82
+ let old_ty = rustc_internal:: stable ( tcx. type_of ( old_def_id) ) . value ;
83
+ let new_ty = rustc_internal:: stable ( tcx. type_of ( new_def_id) ) . value ;
84
+ let TyKind :: RigidTy ( RigidTy :: FnDef ( _, mut old_args) ) = old_ty. kind ( ) else {
85
+ unreachable ! ( "Expected function, but found {old_ty}" )
86
+ } ;
87
+ let TyKind :: RigidTy ( RigidTy :: FnDef ( _, new_args) ) = new_ty. kind ( ) else {
88
+ unreachable ! ( "Expected function, but found {new_ty}" )
89
+ } ;
90
+ if let Some ( idx) = contract_host_param ( tcx, old_def, new_def) {
91
+ old_args. 0 . remove ( idx) ;
92
+ }
93
+
94
+ // TODO: We should check for the parameter type too or replacement will fail.
95
+ if old_args. 0 . len ( ) != new_args. 0 . len ( ) {
67
96
let msg = format ! (
68
97
"mismatch in the number of generic parameters: original function/method `{}` takes {} generic parameters(s), stub `{}` takes {}" ,
69
98
old_def. name( ) ,
70
- old_num_generics ,
99
+ old_args . 0 . len ( ) ,
71
100
new_def. name( ) ,
72
- stub_num_generics
101
+ new_args . 0 . len ( ) ,
73
102
) ;
74
103
return Err ( msg) ;
75
104
}
0 commit comments