Skip to content

Commit 6b74503

Browse files
authored
Auto merge of #35877 - KiChjang:issue-35869, r=arielb1
Fix ICE when arg types can't be found in impl/trait methods while comparing Fixes #35869.
2 parents b7e2157 + 3d9cf30 commit 6b74503

File tree

2 files changed

+122
-63
lines changed

2 files changed

+122
-63
lines changed

src/librustc_typeck/check/compare_method.rs

+85-63
Original file line numberDiff line numberDiff line change
@@ -299,11 +299,10 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
299299
impl_m_span,
300300
impl_m_body_id,
301301
&impl_sig);
302-
let impl_args = impl_sig.inputs.clone();
303302
let impl_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
304303
unsafety: impl_m.fty.unsafety,
305304
abi: impl_m.fty.abi,
306-
sig: ty::Binder(impl_sig)
305+
sig: ty::Binder(impl_sig.clone())
307306
}));
308307
debug!("compare_impl_method: impl_fty={:?}", impl_fty);
309308

@@ -318,11 +317,10 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
318317
impl_m_span,
319318
impl_m_body_id,
320319
&trait_sig);
321-
let trait_args = trait_sig.inputs.clone();
322320
let trait_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
323321
unsafety: trait_m.fty.unsafety,
324322
abi: trait_m.fty.abi,
325-
sig: ty::Binder(trait_sig)
323+
sig: ty::Binder(trait_sig.clone())
326324
}));
327325

328326
debug!("compare_impl_method: trait_fty={:?}", trait_fty);
@@ -332,65 +330,9 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
332330
impl_fty,
333331
trait_fty);
334332

335-
let impl_m_iter = match tcx.map.expect_impl_item(impl_m_node_id).node {
336-
ImplItemKind::Method(ref impl_m_sig, _) => impl_m_sig.decl.inputs.iter(),
337-
_ => bug!("{:?} is not a method", impl_m)
338-
};
339-
340-
let (impl_err_span, trait_err_span) = match terr {
341-
TypeError::Mutability => {
342-
if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
343-
let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node {
344-
TraitItem_::MethodTraitItem(ref trait_m_sig, _) =>
345-
trait_m_sig.decl.inputs.iter(),
346-
_ => bug!("{:?} is not a MethodTraitItem", trait_m)
347-
};
348-
349-
impl_m_iter.zip(trait_m_iter).find(|&(ref impl_arg, ref trait_arg)| {
350-
match (&impl_arg.ty.node, &trait_arg.ty.node) {
351-
(&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) |
352-
(&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) =>
353-
impl_mt.mutbl != trait_mt.mutbl,
354-
_ => false
355-
}
356-
}).map(|(ref impl_arg, ref trait_arg)| {
357-
match (impl_arg.to_self(), trait_arg.to_self()) {
358-
(Some(impl_self), Some(trait_self)) =>
359-
(impl_self.span, Some(trait_self.span)),
360-
(None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)),
361-
_ => bug!("impl and trait fns have different first args, \
362-
impl: {:?}, trait: {:?}", impl_arg, trait_arg)
363-
}
364-
}).unwrap_or((origin.span(), tcx.map.span_if_local(trait_m.def_id)))
365-
} else {
366-
(origin.span(), tcx.map.span_if_local(trait_m.def_id))
367-
}
368-
}
369-
TypeError::Sorts(ExpectedFound { expected, found }) => {
370-
if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
371-
let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node {
372-
TraitItem_::MethodTraitItem(ref trait_m_sig, _) =>
373-
trait_m_sig.decl.inputs.iter(),
374-
_ => bug!("{:?} is not a MethodTraitItem", trait_m)
375-
};
376-
let impl_iter = impl_args.iter();
377-
let trait_iter = trait_args.iter();
378-
let arg_idx = impl_iter.zip(trait_iter)
379-
.position(|(impl_arg_ty, trait_arg_ty)| {
380-
*impl_arg_ty == found && *trait_arg_ty == expected
381-
}).unwrap();
382-
impl_m_iter.zip(trait_m_iter)
383-
.nth(arg_idx)
384-
.map(|(impl_arg, trait_arg)|
385-
(impl_arg.ty.span, Some(trait_arg.ty.span)))
386-
.unwrap_or(
387-
(origin.span(), tcx.map.span_if_local(trait_m.def_id)))
388-
} else {
389-
(origin.span(), tcx.map.span_if_local(trait_m.def_id))
390-
}
391-
}
392-
_ => (origin.span(), tcx.map.span_if_local(trait_m.def_id))
393-
};
333+
let (impl_err_span, trait_err_span) =
334+
extract_spans_for_error_reporting(&infcx, &terr, origin, impl_m,
335+
impl_sig, trait_m, trait_sig);
394336

395337
let origin = TypeOrigin::MethodCompatCheck(impl_err_span);
396338

@@ -479,6 +421,86 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
479421

480422
return true;
481423
}
424+
425+
fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
426+
terr: &TypeError,
427+
origin: TypeOrigin,
428+
impl_m: &ty::Method,
429+
impl_sig: ty::FnSig<'tcx>,
430+
trait_m: &ty::Method,
431+
trait_sig: ty::FnSig<'tcx>)
432+
-> (Span, Option<Span>) {
433+
let tcx = infcx.tcx;
434+
let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap();
435+
let (impl_m_output, impl_m_iter) = match tcx.map.expect_impl_item(impl_m_node_id).node {
436+
ImplItemKind::Method(ref impl_m_sig, _) =>
437+
(&impl_m_sig.decl.output, impl_m_sig.decl.inputs.iter()),
438+
_ => bug!("{:?} is not a method", impl_m)
439+
};
440+
441+
match *terr {
442+
TypeError::Mutability => {
443+
if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
444+
let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node {
445+
TraitItem_::MethodTraitItem(ref trait_m_sig, _) =>
446+
trait_m_sig.decl.inputs.iter(),
447+
_ => bug!("{:?} is not a MethodTraitItem", trait_m)
448+
};
449+
450+
impl_m_iter.zip(trait_m_iter).find(|&(ref impl_arg, ref trait_arg)| {
451+
match (&impl_arg.ty.node, &trait_arg.ty.node) {
452+
(&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) |
453+
(&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) =>
454+
impl_mt.mutbl != trait_mt.mutbl,
455+
_ => false
456+
}
457+
}).map(|(ref impl_arg, ref trait_arg)| {
458+
match (impl_arg.to_self(), trait_arg.to_self()) {
459+
(Some(impl_self), Some(trait_self)) =>
460+
(impl_self.span, Some(trait_self.span)),
461+
(None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)),
462+
_ => bug!("impl and trait fns have different first args, \
463+
impl: {:?}, trait: {:?}", impl_arg, trait_arg)
464+
}
465+
}).unwrap_or((origin.span(), tcx.map.span_if_local(trait_m.def_id)))
466+
} else {
467+
(origin.span(), tcx.map.span_if_local(trait_m.def_id))
468+
}
469+
}
470+
TypeError::Sorts(ExpectedFound { .. }) => {
471+
if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
472+
let (trait_m_output, trait_m_iter) =
473+
match tcx.map.expect_trait_item(trait_m_node_id).node {
474+
TraitItem_::MethodTraitItem(ref trait_m_sig, _) =>
475+
(&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter()),
476+
_ => bug!("{:?} is not a MethodTraitItem", trait_m)
477+
};
478+
479+
let impl_iter = impl_sig.inputs.iter();
480+
let trait_iter = trait_sig.inputs.iter();
481+
impl_iter.zip(trait_iter).zip(impl_m_iter).zip(trait_m_iter)
482+
.filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| {
483+
match infcx.sub_types(true, origin, trait_arg_ty, impl_arg_ty) {
484+
Ok(_) => None,
485+
Err(_) => Some((impl_arg.ty.span, Some(trait_arg.ty.span)))
486+
}
487+
})
488+
.next()
489+
.unwrap_or_else(|| {
490+
if infcx.sub_types(false, origin, impl_sig.output,
491+
trait_sig.output).is_err() {
492+
(impl_m_output.span(), Some(trait_m_output.span()))
493+
} else {
494+
(origin.span(), tcx.map.span_if_local(trait_m.def_id))
495+
}
496+
})
497+
} else {
498+
(origin.span(), tcx.map.span_if_local(trait_m.def_id))
499+
}
500+
}
501+
_ => (origin.span(), tcx.map.span_if_local(trait_m.def_id))
502+
}
503+
}
482504
}
483505

484506
pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,

src/test/compile-fail/issue-35869.rs

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(conservative_impl_trait)]
12+
13+
trait Foo {
14+
fn foo(fn(u8) -> ()); //~ NOTE type in trait
15+
fn bar(Option<u8>); //~ NOTE type in trait
16+
fn baz((u8, u16)); //~ NOTE type in trait
17+
fn qux() -> u8; //~ NOTE type in trait
18+
}
19+
20+
struct Bar;
21+
22+
impl Foo for Bar {
23+
fn foo(_: fn(u16) -> ()) {}
24+
//~^ ERROR method `foo` has an incompatible type for trait
25+
//~| NOTE expected u8
26+
fn bar(_: Option<u16>) {}
27+
//~^ ERROR method `bar` has an incompatible type for trait
28+
//~| NOTE expected u8
29+
fn baz(_: (u16, u16)) {}
30+
//~^ ERROR method `baz` has an incompatible type for trait
31+
//~| NOTE expected u8
32+
fn qux() -> u16 { 5u16 }
33+
//~^ ERROR method `qux` has an incompatible type for trait
34+
//~| NOTE expected u8
35+
}
36+
37+
fn main() {}

0 commit comments

Comments
 (0)