Skip to content

Commit 1ae32de

Browse files
committed
Auto merge of #23438 - nikomatsakis:issue-23435-default-methods-with-where-clauses, r=nrc
Fixes #23435
2 parents ea8b82e + bd2096c commit 1ae32de

File tree

5 files changed

+172
-50
lines changed

5 files changed

+172
-50
lines changed

src/librustc/util/ppaux.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1053,10 +1053,11 @@ impl<'tcx> Repr<'tcx> for ty::Variance {
10531053

10541054
impl<'tcx> Repr<'tcx> for ty::Method<'tcx> {
10551055
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
1056-
format!("method(name: {}, generics: {}, fty: {}, \
1056+
format!("method(name: {}, generics: {}, predicates: {}, fty: {}, \
10571057
explicit_self: {}, vis: {}, def_id: {})",
10581058
self.name.repr(tcx),
10591059
self.generics.repr(tcx),
1060+
self.predicates.repr(tcx),
10601061
self.fty.repr(tcx),
10611062
self.explicit_self.repr(tcx),
10621063
self.vis.repr(tcx),

src/librustc_trans/trans/common.rs

+53-14
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ use arena::TypedArena;
4646
use libc::{c_uint, c_char};
4747
use std::ffi::CString;
4848
use std::cell::{Cell, RefCell};
49+
use std::result::Result as StdResult;
4950
use std::vec::Vec;
5051
use syntax::ast::Ident;
5152
use syntax::ast;
@@ -997,9 +998,9 @@ pub fn expr_ty_adjusted<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, ex: &ast::Expr) ->
997998
/// do not (necessarily) resolve all nested obligations on the impl. Note that type check should
998999
/// guarantee to us that all nested obligations *could be* resolved if we wanted to.
9991000
pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
1000-
span: Span,
1001-
trait_ref: ty::PolyTraitRef<'tcx>)
1002-
-> traits::Vtable<'tcx, ()>
1001+
span: Span,
1002+
trait_ref: ty::PolyTraitRef<'tcx>)
1003+
-> traits::Vtable<'tcx, ()>
10031004
{
10041005
let tcx = ccx.tcx();
10051006

@@ -1058,7 +1059,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
10581059
let vtable = selection.map_move_nested(|predicate| {
10591060
fulfill_cx.register_predicate_obligation(&infcx, predicate);
10601061
});
1061-
let vtable = drain_fulfillment_cx(span, &infcx, &mut fulfill_cx, &vtable);
1062+
let vtable = drain_fulfillment_cx_or_panic(span, &infcx, &mut fulfill_cx, &vtable);
10621063

10631064
info!("Cache miss: {}", trait_ref.repr(ccx.tcx()));
10641065
ccx.trait_cache().borrow_mut().insert(trait_ref,
@@ -1067,6 +1068,22 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
10671068
vtable
10681069
}
10691070

1071+
pub fn predicates_hold<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
1072+
predicates: Vec<ty::Predicate<'tcx>>)
1073+
-> bool
1074+
{
1075+
debug!("predicates_hold(predicates={})",
1076+
predicates.repr(ccx.tcx()));
1077+
1078+
let infcx = infer::new_infer_ctxt(ccx.tcx());
1079+
let mut fulfill_cx = traits::FulfillmentContext::new();
1080+
for predicate in predicates {
1081+
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(), predicate);
1082+
fulfill_cx.register_predicate_obligation(&infcx, obligation);
1083+
}
1084+
drain_fulfillment_cx(DUMMY_SP, &infcx, &mut fulfill_cx, &()).is_ok()
1085+
}
1086+
10701087
pub struct NormalizingClosureTyper<'a,'tcx:'a> {
10711088
param_env: ty::ParameterEnvironment<'a, 'tcx>
10721089
}
@@ -1114,11 +1131,36 @@ impl<'a,'tcx> ty::ClosureTyper<'tcx> for NormalizingClosureTyper<'a,'tcx> {
11141131
}
11151132
}
11161133

1134+
pub fn drain_fulfillment_cx_or_panic<'a,'tcx,T>(span: Span,
1135+
infcx: &infer::InferCtxt<'a,'tcx>,
1136+
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
1137+
result: &T)
1138+
-> T
1139+
where T : TypeFoldable<'tcx> + Repr<'tcx>
1140+
{
1141+
match drain_fulfillment_cx(span, infcx, fulfill_cx, result) {
1142+
Ok(v) => v,
1143+
Err(errors) => {
1144+
infcx.tcx.sess.span_bug(
1145+
span,
1146+
&format!("Encountered errors `{}` fulfilling during trans",
1147+
errors.repr(infcx.tcx)));
1148+
}
1149+
}
1150+
}
1151+
1152+
/// Finishes processes any obligations that remain in the fulfillment
1153+
/// context, and then "freshens" and returns `result`. This is
1154+
/// primarily used during normalization and other cases where
1155+
/// processing the obligations in `fulfill_cx` may cause type
1156+
/// inference variables that appear in `result` to be unified, and
1157+
/// hence we need to process those obligations to get the complete
1158+
/// picture of the type.
11171159
pub fn drain_fulfillment_cx<'a,'tcx,T>(span: Span,
1118-
infcx: &infer::InferCtxt<'a,'tcx>,
1119-
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
1120-
result: &T)
1121-
-> T
1160+
infcx: &infer::InferCtxt<'a,'tcx>,
1161+
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
1162+
result: &T)
1163+
-> StdResult<T,Vec<traits::FulfillmentError<'tcx>>>
11221164
where T : TypeFoldable<'tcx> + Repr<'tcx>
11231165
{
11241166
debug!("drain_fulfillment_cx(result={})",
@@ -1131,16 +1173,13 @@ pub fn drain_fulfillment_cx<'a,'tcx,T>(span: Span,
11311173
match fulfill_cx.select_all_or_error(infcx, &typer) {
11321174
Ok(()) => { }
11331175
Err(errors) => {
1176+
// We always want to surface any overflow errors, no matter what.
11341177
if errors.iter().all(|e| e.is_overflow()) {
1135-
// See Ok(None) case above.
11361178
infcx.tcx.sess.span_fatal(
11371179
span,
11381180
"reached the recursion limit during monomorphization");
11391181
} else {
1140-
infcx.tcx.sess.span_bug(
1141-
span,
1142-
&format!("Encountered errors `{}` fulfilling during trans",
1143-
errors.repr(infcx.tcx)));
1182+
return Err(errors);
11441183
}
11451184
}
11461185
}
@@ -1150,7 +1189,7 @@ pub fn drain_fulfillment_cx<'a,'tcx,T>(span: Span,
11501189
// sort of overkill because we do not expect there to be any
11511190
// unbound type variables, hence no `TyFresh` types should ever be
11521191
// inserted.
1153-
result.fold_with(&mut infcx.freshener())
1192+
Ok(result.fold_with(&mut infcx.freshener()))
11541193
}
11551194

11561195
// Key used to lookup values supplied for type parameters in an expr.

src/librustc_trans/trans/meth.rs

+81-34
Original file line numberDiff line numberDiff line change
@@ -765,9 +765,15 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
765765
impl_id: ast::DefId,
766766
substs: subst::Substs<'tcx>,
767767
param_substs: &'tcx subst::Substs<'tcx>)
768-
-> Vec<ValueRef> {
768+
-> Vec<ValueRef>
769+
{
769770
let tcx = ccx.tcx();
770771

772+
debug!("emit_vtable_methods(impl_id={}, substs={}, param_substs={})",
773+
impl_id.repr(tcx),
774+
substs.repr(tcx),
775+
param_substs.repr(tcx));
776+
771777
let trt_id = match ty::impl_trait_ref(tcx, impl_id) {
772778
Some(t_id) => t_id.def_id,
773779
None => ccx.sess().bug("make_impl_vtable: don't know how to \
@@ -777,41 +783,82 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
777783
ty::populate_implementations_for_trait_if_necessary(tcx, trt_id);
778784

779785
let trait_item_def_ids = ty::trait_item_def_ids(tcx, trt_id);
780-
trait_item_def_ids.iter().flat_map(|method_def_id| {
781-
let method_def_id = method_def_id.def_id();
782-
let name = ty::impl_or_trait_item(tcx, method_def_id).name();
783-
// The substitutions we have are on the impl, so we grab
784-
// the method type from the impl to substitute into.
785-
let m_id = method_with_name(ccx, impl_id, name);
786-
let ti = ty::impl_or_trait_item(tcx, m_id);
787-
match ti {
788-
ty::MethodTraitItem(m) => {
789-
debug!("(making impl vtable) emitting method {} at subst {}",
790-
m.repr(tcx),
791-
substs.repr(tcx));
792-
if m.generics.has_type_params(subst::FnSpace) ||
793-
ty::type_has_self(ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(m.fty.clone())))
794-
{
795-
debug!("(making impl vtable) method has self or type \
796-
params: {}",
797-
token::get_name(name));
798-
Some(C_null(Type::nil(ccx).ptr_to())).into_iter()
799-
} else {
800-
let fn_ref = trans_fn_ref_with_substs(
801-
ccx,
802-
m_id,
803-
ExprId(0),
804-
param_substs,
805-
substs.clone()).val;
806-
807-
Some(fn_ref).into_iter()
808-
}
786+
trait_item_def_ids
787+
.iter()
788+
789+
// Filter out the associated types.
790+
.filter_map(|item_def_id| {
791+
match *item_def_id {
792+
ty::MethodTraitItemId(def_id) => Some(def_id),
793+
ty::TypeTraitItemId(_) => None,
794+
}
795+
})
796+
797+
// Now produce pointers for each remaining method. If the
798+
// method could never be called from this object, just supply
799+
// null.
800+
.map(|trait_method_def_id| {
801+
debug!("emit_vtable_methods: trait_method_def_id={}",
802+
trait_method_def_id.repr(tcx));
803+
804+
let trait_method_type = match ty::impl_or_trait_item(tcx, trait_method_def_id) {
805+
ty::MethodTraitItem(m) => m,
806+
ty::TypeTraitItem(_) => ccx.sess().bug("should be a method, not assoc type")
807+
};
808+
let name = trait_method_type.name;
809+
810+
debug!("emit_vtable_methods: trait_method_type={}",
811+
trait_method_type.repr(tcx));
812+
813+
// The substitutions we have are on the impl, so we grab
814+
// the method type from the impl to substitute into.
815+
let impl_method_def_id = method_with_name(ccx, impl_id, name);
816+
let impl_method_type = match ty::impl_or_trait_item(tcx, impl_method_def_id) {
817+
ty::MethodTraitItem(m) => m,
818+
ty::TypeTraitItem(_) => ccx.sess().bug("should be a method, not assoc type")
819+
};
820+
821+
debug!("emit_vtable_methods: m={}",
822+
impl_method_type.repr(tcx));
823+
824+
let nullptr = C_null(Type::nil(ccx).ptr_to());
825+
826+
if impl_method_type.generics.has_type_params(subst::FnSpace) {
827+
debug!("emit_vtable_methods: generic");
828+
return nullptr;
809829
}
810-
ty::TypeTraitItem(_) => {
811-
None.into_iter()
830+
831+
let bare_fn_ty =
832+
ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(impl_method_type.fty.clone()));
833+
if ty::type_has_self(bare_fn_ty) {
834+
debug!("emit_vtable_methods: type_has_self {}",
835+
bare_fn_ty.repr(tcx));
836+
return nullptr;
812837
}
813-
}
814-
}).collect()
838+
839+
// If this is a default method, it's possible that it
840+
// relies on where clauses that do not hold for this
841+
// particular set of type parameters. Note that this
842+
// method could then never be called, so we do not want to
843+
// try and trans it, in that case. Issue #23435.
844+
if ty::provided_source(tcx, impl_method_def_id).is_some() {
845+
let predicates =
846+
monomorphize::apply_param_substs(tcx,
847+
&substs,
848+
&impl_method_type.predicates.predicates);
849+
if !predicates_hold(ccx, predicates.into_vec()) {
850+
debug!("emit_vtable_methods: predicates do not hold");
851+
return nullptr;
852+
}
853+
}
854+
855+
trans_fn_ref_with_substs(ccx,
856+
impl_method_def_id,
857+
ExprId(0),
858+
param_substs,
859+
substs.clone()).val
860+
})
861+
.collect()
815862
}
816863

817864
/// Generates the code to convert from a pointer (`Box<T>`, `&T`, etc) into an object

src/librustc_trans/trans/monomorphize.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T
339339
for obligation in obligations {
340340
fulfill_cx.register_predicate_obligation(&infcx, obligation);
341341
}
342-
let result = drain_fulfillment_cx(DUMMY_SP, &infcx, &mut fulfill_cx, &result);
342+
let result = drain_fulfillment_cx_or_panic(DUMMY_SP, &infcx, &mut fulfill_cx, &result);
343343

344344
result
345345
}

src/test/run-pass/issue-23435.rs

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2015 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+
// Test that we do not ICE when a default method implementation has
12+
// requirements (in this case, `Self : Baz`) that do not hold for some
13+
// specific impl (in this case, `Foo : Bar`). This causes problems
14+
// only when building a vtable, because that goes along and
15+
// instantiates all the methods, even those that could not otherwise
16+
// be called.
17+
18+
struct Foo {
19+
x: i32
20+
}
21+
22+
trait Bar {
23+
fn bar(&self) where Self : Baz { self.baz(); }
24+
}
25+
26+
trait Baz {
27+
fn baz(&self);
28+
}
29+
30+
impl Bar for Foo {
31+
}
32+
33+
fn main() {
34+
let x: &Bar = &Foo { x: 22 };
35+
}

0 commit comments

Comments
 (0)