@@ -249,33 +249,61 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
249249 {
250250 let mut orig_values = SmallVec :: new ( ) ;
251251 let self_ty = self . infcx . canonicalize_data ( & self_ty, & mut orig_values) ;
252+ // XXX: consider caching this "whole op" here.
252253 let steps = if mode == Mode :: MethodCall {
253254 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+ } )
265257 } 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+ } ;
275271
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) ) ) ;
277304
278- } ;
305+ }
306+ }
279307
280308 debug ! ( "ProbeContext: steps for self_ty={:?} are {:?}" ,
281309 self_ty,
@@ -300,86 +328,103 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
300328 }
301329}
302330
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
310331
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 ( ) ;
312381 let mut reached_raw_pointer = false ;
313382 let mut steps: Vec < _ > = autoderef. by_ref ( )
314383 . 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
326405 } )
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+ } ) ;
328418
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
377420 }
421+ _ => None
422+ }
378423
379- debug ! ( "create_steps: steps={:?}" , steps) ;
424+ debug ! ( "create_steps: steps={:?} error={:?} " , steps, error ) ;
380425
381- Some ( steps )
382- }
426+ CreateStepsResult { steps , bad_ty }
427+ }
383428
384429
385430impl < ' a , ' gcx , ' tcx > ProbeContext < ' a , ' gcx , ' tcx > {
0 commit comments