@@ -249,33 +249,61 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
249
249
{
250
250
let mut orig_values = SmallVec :: new ( ) ;
251
251
let self_ty = self . infcx . canonicalize_data ( & self_ty, & mut orig_values) ;
252
+ // XXX: consider caching this "whole op" here.
252
253
let steps = if mode == Mode :: MethodCall {
253
254
tcx. infer_ctxt ( ) . enter ( |ref infcx| {
254
- match create_steps ( infcx, span, scope_expr_id, self_ty, is_suggestion) {
255
- Some ( steps) => Ok ( steps) ,
256
- None => {
257
- return Err ( MethodError :: NoMatch ( NoMatchData :: new ( Vec :: new ( ) ,
258
- Vec :: new ( ) ,
259
- Vec :: new ( ) ,
260
- None ,
261
- mode) ) )
262
- }
263
- }
264
- } ) ?;
255
+ create_steps_inner ( infcx, orig_values, self . param_env , span, self_ty)
256
+ } )
265
257
} else {
266
- vec ! [ CandidateStep {
267
- self_ty,
268
- autoderefs: 0 ,
269
- from_unsafe_deref: false ,
270
- unsize: false ,
271
- } ] ;
272
- }
273
-
274
- let steps =
258
+ // XXX: don't make an inference context for nothing here
259
+ tcx. infer_ctxt ( ) . enter ( |ref infcx| {
260
+ CreateStepsResult {
261
+ steps : vec ! [ CandidateStep {
262
+ self_ty: do_make_query_result( infcx, orig_values, self_ty) ,
263
+ autoderefs: 0 ,
264
+ from_unsafe_deref: false ,
265
+ unsize: false ,
266
+ } ] ,
267
+ bad_ty : None
268
+ }
269
+ } )
270
+ } ;
275
271
276
- } else {
272
+ if let Some ( CreateStepsBadTy { reached_raw_pointer, ty } ) = steps. bad_ty {
273
+ // Ended in an inference variable. If we are doing
274
+ // a real method lookup, this is a hard error because it's
275
+ // possible that there will be multiple applicable methods.
276
+ if !is_suggestion. 0
277
+ && reached_raw_pointer
278
+ && !self . tcx . features ( ) . arbitrary_self_types
279
+ {
280
+ // this case used to be allowed by the compiler,
281
+ // so we do a future-compat lint here for the 2015 edition
282
+ // (see https://github.com/rust-lang/rust/issues/46906)
283
+ if self . tcx . sess . rust_2018 ( ) {
284
+ span_err ! ( self . tcx. sess, span, E0699 ,
285
+ "the type of this value must be known \
286
+ to call a method on a raw pointer on it") ;
287
+ } else {
288
+ self . tcx . lint_node (
289
+ lint:: builtin:: TYVAR_BEHIND_RAW_POINTER ,
290
+ scope_expr_id,
291
+ span,
292
+ "type annotations needed" ) ;
293
+ }
294
+ } else {
295
+ let ty = self . instantiate_query_result ( & orig_values, & ty)
296
+ . unwrap_or_else ( || span_bug ! ( span, "instantiating {:?} failed?" , ty) ) ;
297
+ let t = self . structurally_resolved_type ( span, final_ty) ;
298
+ assert_eq ! ( t, self . tcx. types. err) ;
299
+ return Err ( MethodError :: NoMatch ( NoMatchData :: new ( Vec :: new ( ) ,
300
+ Vec :: new ( ) ,
301
+ Vec :: new ( ) ,
302
+ None ,
303
+ mode) ) ) ;
277
304
278
- } ;
305
+ }
306
+ }
279
307
280
308
debug ! ( "ProbeContext: steps for self_ty={:?} are {:?}" ,
281
309
self_ty,
@@ -300,86 +328,103 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
300
328
}
301
329
}
302
330
303
- fn create_steps ( & self ,
304
- span : Span ,
305
- scope_expr_id : ast:: NodeId ,
306
- self_ty : Ty < ' tcx > ,
307
- is_suggestion : IsSuggestion )
308
- -> Option < Vec < CandidateStep < ' tcx > > > {
309
- // FIXME: we don't need to create the entire steps in one pass
310
331
311
- let mut autoderef = self . autoderef ( span, self_ty) . include_raw_pointers ( ) ;
332
+ fn do_instantiate_query_result < ' a , ' gcx , ' tcx > ( fcx : & ' a FnCtxt < ' a , ' gcx , ' tcx > ,
333
+ param_env : ty:: ParamEnv < ' tcx > ,
334
+ inference_vars : CanonicalVarValues < ' tcx > ,
335
+ ty : Ty < ' gcx > )
336
+ -> Canonical < ' gcx , QueryResult < ' gcx , Ty < ' gcx > > >
337
+ {
338
+ infcx. canonicalize_response ( & QueryResult {
339
+ var_values : inference_vars,
340
+ region_constraints : vec ! [ ] ,
341
+ certainty : Certainity :: Proven , // This field is not used by typeck
342
+ value : ty,
343
+ } )
344
+ }
345
+ }
346
+
347
+ #[ derive( Debug ) ]
348
+ struct CreateStepsResult < ' gcx > {
349
+ steps : Vec < CandidateStep < ' gcx > > ,
350
+ opt_bad_ty : Option < CreateStepsBadTy < ' gcx > >
351
+ }
352
+
353
+ #[ derive( Debug ) ]
354
+ struct CreateStepsBadTy < ' gcx > {
355
+ reached_raw_pointer : bool ,
356
+ ty : Canonical < ' gcx , QueryResult < ' gcx , Ty < ' gcx > > > ,
357
+ }
358
+
359
+ fn do_make_query_result < ' a , ' gcx , ' tcx > ( infcx : & ' a InferCtxt < ' a , ' gcx , ' tcx > ,
360
+ inference_vars : CanonicalVarValues < ' tcx > ,
361
+ ty : Ty < ' gcx > )
362
+ -> Canonical < ' gcx , QueryResult < ' gcx , Ty < ' gcx > > >
363
+ {
364
+ infcx. canonicalize_response ( & QueryResult {
365
+ var_values : inference_vars,
366
+ region_constraints : vec ! [ ] ,
367
+ certainty : Certainity :: Proven , // This field is not used by typeck
368
+ value : ty,
369
+ } )
370
+ }
371
+
372
+ fn create_steps_inner < ' a , ' gcx , ' tcx > ( infcx : & ' a InferCtxt < ' a , ' gcx , ' tcx > ,
373
+ inference_vars : CanonicalVarValues < ' tcx > ,
374
+ param_env : ty:: ParamEnv < ' tcx > ,
375
+ span : Span ,
376
+ self_ty : Canonical < ' gcx , Ty < ' gcx > > )
377
+ -> CreateStepsResult < ' gcx >
378
+ {
379
+ let mut autoderef = Autoderef :: new ( infcx, param_env, DUMMY_NODE_ID , span, self_ty)
380
+ . include_raw_pointers ( ) ;
312
381
let mut reached_raw_pointer = false ;
313
382
let mut steps: Vec < _ > = autoderef. by_ref ( )
314
383
. map ( |( ty, d) | {
315
- let step = CandidateStep {
316
- self_ty : ty,
317
- autoderefs : d,
318
- from_unsafe_deref : reached_raw_pointer,
319
- unsize : false ,
320
- } ;
321
- if let ty:: RawPtr ( _) = ty. sty {
322
- // all the subsequent steps will be from_unsafe_deref
323
- reached_raw_pointer = true ;
324
- }
325
- step
384
+ let step = CandidateStep {
385
+ self_ty : do_make_query_result ( infcx, inference_vars, infcx. tcx . mk_slice ( ty) ) ,
386
+ autoderefs : d,
387
+ from_unsafe_deref : reached_raw_pointer,
388
+ unsize : false ,
389
+ } ;
390
+ if let ty:: RawPtr ( _) = ty. sty {
391
+ // all the subsequent steps will be from_unsafe_deref
392
+ reached_raw_pointer = true ;
393
+ }
394
+ step
395
+ } )
396
+ . collect ( ) ;
397
+
398
+ let final_ty = autoderef. maybe_ambiguous_final_ty ( ) ;
399
+ let opt_bad_ty = match final_ty. sty {
400
+ ty:: Infer ( ty:: TyVar ( _) ) |
401
+ ty:: Error => {
402
+ Some ( CreateStepsBadTy {
403
+ reached_raw_pointer,
404
+ ty : final_ty
326
405
} )
327
- . collect ( ) ;
406
+ }
407
+ ty:: Array ( elem_ty, _) => {
408
+ let dereferences = steps. len ( ) - 1 ;
409
+
410
+ steps. push ( CandidateStep {
411
+ self_ty : do_make_query_result ( infcx, inference_vars, infcx. tcx . mk_slice ( elem_ty) ) ,
412
+ autoderefs : dereferences,
413
+ // this could be from an unsafe deref if we had
414
+ // a *mut/const [T; N]
415
+ from_unsafe_deref : reached_raw_pointer,
416
+ unsize : true ,
417
+ } ) ;
328
418
329
- let final_ty = autoderef. maybe_ambiguous_final_ty ( ) ;
330
- match final_ty. sty {
331
- ty:: Infer ( ty:: TyVar ( _) ) => {
332
- // Ended in an inference variable. If we are doing
333
- // a real method lookup, this is a hard error because it's
334
- // possible that there will be multiple applicable methods.
335
- if !is_suggestion. 0 {
336
- if reached_raw_pointer
337
- && !self . tcx . features ( ) . arbitrary_self_types {
338
- // this case used to be allowed by the compiler,
339
- // so we do a future-compat lint here for the 2015 edition
340
- // (see https://github.com/rust-lang/rust/issues/46906)
341
- if self . tcx . sess . rust_2018 ( ) {
342
- span_err ! ( self . tcx. sess, span, E0699 ,
343
- "the type of this value must be known \
344
- to call a method on a raw pointer on it") ;
345
- } else {
346
- self . tcx . lint_node (
347
- lint:: builtin:: TYVAR_BEHIND_RAW_POINTER ,
348
- scope_expr_id,
349
- span,
350
- "type annotations needed" ) ;
351
- }
352
- } else {
353
- let t = self . structurally_resolved_type ( span, final_ty) ;
354
- assert_eq ! ( t, self . tcx. types. err) ;
355
- return None
356
- }
357
- } else {
358
- // If we're just looking for suggestions,
359
- // though, ambiguity is no big thing, we can
360
- // just ignore it.
361
- }
362
- }
363
- ty:: Array ( elem_ty, _) => {
364
- let dereferences = steps. len ( ) - 1 ;
365
-
366
- steps. push ( CandidateStep {
367
- self_ty : self . tcx . mk_slice ( elem_ty) ,
368
- autoderefs : dereferences,
369
- // this could be from an unsafe deref if we had
370
- // a *mut/const [T; N]
371
- from_unsafe_deref : reached_raw_pointer,
372
- unsize : true ,
373
- } ) ;
374
- }
375
- ty:: Error => return None ,
376
- _ => ( ) ,
419
+ None
377
420
}
421
+ _ => None
422
+ }
378
423
379
- debug ! ( "create_steps: steps={:?}" , steps) ;
424
+ debug ! ( "create_steps: steps={:?} error={:?} " , steps, error ) ;
380
425
381
- Some ( steps )
382
- }
426
+ CreateStepsResult { steps , bad_ty }
427
+ }
383
428
384
429
385
430
impl < ' a , ' gcx , ' tcx > ProbeContext < ' a , ' gcx , ' tcx > {
0 commit comments