@@ -19,9 +19,10 @@ use rustc_hir::{
19
19
use rustc_hir:: { MethodKind , Target , Unsafety } ;
20
20
use rustc_middle:: hir:: nested_filter;
21
21
use rustc_middle:: middle:: resolve_bound_vars:: ObjectLifetimeDefault ;
22
- use rustc_middle:: ty:: fast_reject:: { DeepRejectCtxt , TreatParams } ;
22
+ use rustc_middle:: traits:: ObligationCause ;
23
+ use rustc_middle:: ty:: error:: { ExpectedFound , TypeError } ;
23
24
use rustc_middle:: ty:: query:: Providers ;
24
- use rustc_middle:: ty:: { ParamEnv , TyCtxt } ;
25
+ use rustc_middle:: ty:: { self , TyCtxt } ;
25
26
use rustc_session:: lint:: builtin:: {
26
27
CONFLICTING_REPR_HINTS , INVALID_DOC_ATTRIBUTES , INVALID_MACRO_EXPORT_ARGUMENTS ,
27
28
UNUSED_ATTRIBUTES ,
@@ -30,6 +31,9 @@ use rustc_session::parse::feature_err;
30
31
use rustc_span:: symbol:: { kw, sym, Symbol } ;
31
32
use rustc_span:: { Span , DUMMY_SP } ;
32
33
use rustc_target:: spec:: abi:: Abi ;
34
+ use rustc_trait_selection:: infer:: { TyCtxtInferExt , ValuePairs } ;
35
+ use rustc_trait_selection:: traits:: error_reporting:: TypeErrCtxtExt ;
36
+ use rustc_trait_selection:: traits:: ObligationCtxt ;
33
37
use std:: cell:: Cell ;
34
38
use std:: collections:: hash_map:: Entry ;
35
39
@@ -2188,100 +2192,99 @@ impl CheckAttrVisitor<'_> {
2188
2192
///
2189
2193
/// If this best effort goes wrong, it will just emit a worse error later (see #102923)
2190
2194
fn check_proc_macro ( & self , hir_id : HirId , target : Target , kind : ProcMacroKind ) {
2191
- let expected_input_count = match kind {
2192
- ProcMacroKind :: Attribute => 2 ,
2193
- ProcMacroKind :: Derive | ProcMacroKind :: FunctionLike => 1 ,
2194
- } ;
2195
-
2196
- let expected_signature = match kind {
2197
- ProcMacroKind :: Attribute => "fn(TokenStream, TokenStream) -> TokenStream" ,
2198
- ProcMacroKind :: Derive | ProcMacroKind :: FunctionLike => "fn(TokenStream) -> TokenStream" ,
2199
- } ;
2195
+ if target != Target :: Fn {
2196
+ return ;
2197
+ }
2200
2198
2201
2199
let tcx = self . tcx ;
2202
- if target == Target :: Fn {
2203
- let Some ( tokenstream) = tcx. get_diagnostic_item ( sym:: TokenStream ) else { return } ;
2204
- let tokenstream = tcx. type_of ( tokenstream) . subst_identity ( ) ;
2205
-
2206
- let id = hir_id. expect_owner ( ) ;
2207
- let hir_sig = tcx. hir ( ) . fn_sig_by_hir_id ( hir_id) . unwrap ( ) ;
2208
-
2209
- let sig =
2210
- tcx. liberate_late_bound_regions ( id. to_def_id ( ) , tcx. fn_sig ( id) . subst_identity ( ) ) ;
2211
- let sig = tcx. normalize_erasing_regions ( ParamEnv :: empty ( ) , sig) ;
2212
-
2213
- // We don't currently require that the function signature is equal to
2214
- // `fn(TokenStream) -> TokenStream`, but instead monomorphizes to
2215
- // `fn(TokenStream) -> TokenStream` after some substitution of generic arguments.
2216
- //
2217
- // Properly checking this means pulling in additional `rustc` crates, so we don't.
2218
- let drcx = DeepRejectCtxt { treat_obligation_params : TreatParams :: AsCandidateKey } ;
2219
-
2220
- if sig. abi != Abi :: Rust {
2221
- tcx. sess . emit_err ( errors:: ProcMacroInvalidAbi {
2222
- span : hir_sig. span ,
2223
- abi : sig. abi . name ( ) ,
2224
- } ) ;
2225
- self . abort . set ( true ) ;
2226
- }
2200
+ let Some ( token_stream_def_id) = tcx. get_diagnostic_item ( sym:: TokenStream ) else { return ; } ;
2201
+ let Some ( token_stream) = tcx. type_of ( token_stream_def_id) . no_bound_vars ( ) else { return ; } ;
2227
2202
2228
- if sig. unsafety == Unsafety :: Unsafe {
2229
- tcx. sess . emit_err ( errors:: ProcMacroUnsafe { span : hir_sig. span } ) ;
2230
- self . abort . set ( true ) ;
2231
- }
2203
+ let def_id = hir_id. expect_owner ( ) . def_id ;
2204
+ let param_env = ty:: ParamEnv :: empty ( ) ;
2232
2205
2233
- let output = sig. output ( ) ;
2206
+ let infcx = tcx. infer_ctxt ( ) . build ( ) ;
2207
+ let ocx = ObligationCtxt :: new ( & infcx) ;
2234
2208
2235
- // Typecheck the output
2236
- if !drcx. types_may_unify ( output, tokenstream) {
2237
- tcx. sess . emit_err ( errors:: ProcMacroTypeError {
2238
- span : hir_sig. decl . output . span ( ) ,
2239
- found : output,
2240
- kind,
2241
- expected_signature,
2242
- } ) ;
2243
- self . abort . set ( true ) ;
2244
- }
2209
+ let span = tcx. def_span ( def_id) ;
2210
+ let fresh_substs = infcx. fresh_substs_for_item ( span, def_id. to_def_id ( ) ) ;
2211
+ let sig = tcx. liberate_late_bound_regions (
2212
+ def_id. to_def_id ( ) ,
2213
+ tcx. fn_sig ( def_id) . subst ( tcx, fresh_substs) ,
2214
+ ) ;
2245
2215
2246
- if sig. inputs ( ) . len ( ) < expected_input_count {
2247
- tcx. sess . emit_err ( errors:: ProcMacroMissingArguments {
2248
- expected_input_count,
2249
- span : hir_sig. span ,
2250
- kind,
2251
- expected_signature,
2252
- } ) ;
2253
- self . abort . set ( true ) ;
2254
- }
2216
+ let mut cause = ObligationCause :: misc ( span, def_id) ;
2217
+ let sig = ocx. normalize ( & cause, param_env, sig) ;
2255
2218
2256
- // Check that the inputs are correct, if there are enough.
2257
- if sig. inputs ( ) . len ( ) >= expected_input_count {
2258
- for ( arg, input) in
2259
- sig. inputs ( ) . iter ( ) . zip ( hir_sig. decl . inputs ) . take ( expected_input_count)
2260
- {
2261
- if !drcx. types_may_unify ( * arg, tokenstream) {
2262
- tcx. sess . emit_err ( errors:: ProcMacroTypeError {
2263
- span : input. span ,
2264
- found : * arg,
2265
- kind,
2266
- expected_signature,
2267
- } ) ;
2268
- self . abort . set ( true ) ;
2219
+ // proc macro is not WF.
2220
+ let errors = ocx. select_where_possible ( ) ;
2221
+ if !errors. is_empty ( ) {
2222
+ return ;
2223
+ }
2224
+
2225
+ let expected_sig = tcx. mk_fn_sig (
2226
+ std:: iter:: repeat ( token_stream) . take ( match kind {
2227
+ ProcMacroKind :: Attribute => 2 ,
2228
+ ProcMacroKind :: Derive | ProcMacroKind :: FunctionLike => 1 ,
2229
+ } ) ,
2230
+ token_stream,
2231
+ false ,
2232
+ Unsafety :: Normal ,
2233
+ Abi :: Rust ,
2234
+ ) ;
2235
+
2236
+ if let Err ( terr) = ocx. eq ( & cause, param_env, expected_sig, sig) {
2237
+ let mut diag = tcx. sess . create_err ( errors:: ProcMacroBadSig { span, kind } ) ;
2238
+
2239
+ let hir_sig = tcx. hir ( ) . fn_sig_by_hir_id ( hir_id) ;
2240
+ if let Some ( hir_sig) = hir_sig {
2241
+ match terr {
2242
+ TypeError :: ArgumentMutability ( idx) | TypeError :: ArgumentSorts ( _, idx) => {
2243
+ if let Some ( ty) = hir_sig. decl . inputs . get ( idx) {
2244
+ diag. set_span ( ty. span ) ;
2245
+ cause. span = ty. span ;
2246
+ } else if idx == hir_sig. decl . inputs . len ( ) {
2247
+ let span = hir_sig. decl . output . span ( ) ;
2248
+ diag. set_span ( span) ;
2249
+ cause. span = span;
2250
+ }
2251
+ }
2252
+ TypeError :: ArgCount => {
2253
+ if let Some ( ty) = hir_sig. decl . inputs . get ( expected_sig. inputs ( ) . len ( ) ) {
2254
+ diag. set_span ( ty. span ) ;
2255
+ cause. span = ty. span ;
2256
+ }
2269
2257
}
2258
+ TypeError :: UnsafetyMismatch ( _) => {
2259
+ // FIXME: Would be nice if we had a span here..
2260
+ }
2261
+ TypeError :: AbiMismatch ( _) => {
2262
+ // FIXME: Would be nice if we had a span here..
2263
+ }
2264
+ TypeError :: VariadicMismatch ( _) => {
2265
+ // FIXME: Would be nice if we had a span here..
2266
+ }
2267
+ _ => { }
2270
2268
}
2271
2269
}
2272
2270
2273
- // Check that there are not too many arguments
2274
- let body_id = tcx. hir ( ) . body_owned_by ( id. def_id ) ;
2275
- let excess = tcx. hir ( ) . body ( body_id) . params . get ( expected_input_count..) ;
2276
- if let Some ( excess @ [ begin @ end] | excess @ [ begin, .., end] ) = excess {
2277
- tcx. sess . emit_err ( errors:: ProcMacroDiffArguments {
2278
- span : begin. span . to ( end. span ) ,
2279
- count : excess. len ( ) ,
2280
- kind,
2281
- expected_signature,
2282
- } ) ;
2283
- self . abort . set ( true ) ;
2284
- }
2271
+ infcx. err_ctxt ( ) . note_type_err (
2272
+ & mut diag,
2273
+ & cause,
2274
+ None ,
2275
+ Some ( ValuePairs :: Sigs ( ExpectedFound { expected : expected_sig, found : sig } ) ) ,
2276
+ terr,
2277
+ false ,
2278
+ false ,
2279
+ ) ;
2280
+ diag. emit ( ) ;
2281
+ self . abort . set ( true ) ;
2282
+ }
2283
+
2284
+ let errors = ocx. select_all_or_error ( ) ;
2285
+ if !errors. is_empty ( ) {
2286
+ infcx. err_ctxt ( ) . report_fulfillment_errors ( & errors) ;
2287
+ self . abort . set ( true ) ;
2285
2288
}
2286
2289
}
2287
2290
}
0 commit comments