normalize fn sig as part of reification
This commit is contained in:
parent
0c26d8fcd1
commit
d5cff0740f
@ -17,7 +17,7 @@
|
||||
use rustc::traits::{self, FulfillmentContext};
|
||||
use rustc::ty::error::TypeError;
|
||||
use rustc::ty::fold::TypeFoldable;
|
||||
use rustc::ty::{self, Ty, TyCtxt, TypeVariants, ToPolyTraitRef};
|
||||
use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeVariants};
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc::mir::*;
|
||||
use rustc::mir::tcx::PlaceTy;
|
||||
@ -193,13 +193,11 @@ fn sanitize_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
|
||||
assert_eq!(def_id, ty_def_id);
|
||||
substs
|
||||
}
|
||||
_ => {
|
||||
span_bug!(
|
||||
self.last_span,
|
||||
"unexpected type for constant function: {:?}",
|
||||
value.ty
|
||||
)
|
||||
}
|
||||
_ => span_bug!(
|
||||
self.last_span,
|
||||
"unexpected type for constant function: {:?}",
|
||||
value.ty
|
||||
),
|
||||
};
|
||||
|
||||
let instantiated_predicates =
|
||||
@ -585,12 +583,8 @@ fn fully_perform_op<OP, R>(
|
||||
span_mirbug!(self, "", "errors selecting obligation: {:?}", e);
|
||||
}
|
||||
|
||||
self.infcx.process_registered_region_obligations(
|
||||
&[],
|
||||
None,
|
||||
self.param_env,
|
||||
self.body_id,
|
||||
);
|
||||
self.infcx
|
||||
.process_registered_region_obligations(&[], None, self.param_env, self.body_id);
|
||||
|
||||
let data = self.infcx.take_and_reset_region_constraints();
|
||||
if !data.is_empty() {
|
||||
@ -1164,18 +1158,16 @@ fn check_rvalue(&mut self, mir: &Mir<'tcx>, rvalue: &Rvalue<'tcx>, location: Loc
|
||||
self.check_aggregate_rvalue(mir, rvalue, ak, ops, location)
|
||||
}
|
||||
|
||||
Rvalue::Repeat(operand, const_usize) => {
|
||||
if const_usize.as_u64() > 1 {
|
||||
let operand_ty = operand.ty(mir, tcx);
|
||||
Rvalue::Repeat(operand, const_usize) => if const_usize.as_u64() > 1 {
|
||||
let operand_ty = operand.ty(mir, tcx);
|
||||
|
||||
let trait_ref = ty::TraitRef {
|
||||
def_id: tcx.lang_items().copy_trait().unwrap(),
|
||||
substs: tcx.mk_substs_trait(operand_ty, &[]),
|
||||
};
|
||||
let trait_ref = ty::TraitRef {
|
||||
def_id: tcx.lang_items().copy_trait().unwrap(),
|
||||
substs: tcx.mk_substs_trait(operand_ty, &[]),
|
||||
};
|
||||
|
||||
self.prove_trait_ref(trait_ref, location);
|
||||
}
|
||||
}
|
||||
self.prove_trait_ref(trait_ref, location);
|
||||
},
|
||||
|
||||
Rvalue::NullaryOp(_, ty) => {
|
||||
let trait_ref = ty::TraitRef {
|
||||
@ -1186,50 +1178,87 @@ fn check_rvalue(&mut self, mir: &Mir<'tcx>, rvalue: &Rvalue<'tcx>, location: Loc
|
||||
self.prove_trait_ref(trait_ref, location);
|
||||
}
|
||||
|
||||
Rvalue::Cast(cast_kind, op, ty) => {
|
||||
match cast_kind {
|
||||
CastKind::ReifyFnPointer => {
|
||||
let ty_fn_ptr_from = tcx.mk_fn_ptr(op.ty(mir, tcx).fn_sig(tcx));
|
||||
Rvalue::Cast(cast_kind, op, ty) => match cast_kind {
|
||||
CastKind::ReifyFnPointer => {
|
||||
let fn_sig = op.ty(mir, tcx).fn_sig(tcx);
|
||||
|
||||
if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.at_self()) {
|
||||
span_mirbug!(self, "", "casting {:?}", terr);
|
||||
}
|
||||
// The type that we see in the fcx is like
|
||||
// `foo::<'a, 'b>`, where `foo` is the path to a
|
||||
// function definition. When we extract the
|
||||
// signature, it comes from the `fn_sig` query,
|
||||
// and hence may contain unnormalized results.
|
||||
let fn_sig = self.normalize(&fn_sig, location);
|
||||
|
||||
let ty_fn_ptr_from = tcx.mk_fn_ptr(fn_sig);
|
||||
|
||||
if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.at_self()) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
rvalue,
|
||||
"equating {:?} with {:?} yields {:?}",
|
||||
ty_fn_ptr_from,
|
||||
ty,
|
||||
terr
|
||||
);
|
||||
}
|
||||
|
||||
CastKind::ClosureFnPointer => {
|
||||
let sig = match op.ty(mir, tcx).sty {
|
||||
ty::TyClosure(def_id, substs) => {
|
||||
substs.closure_sig_ty(def_id, tcx).fn_sig(tcx)
|
||||
}
|
||||
_ => bug!(),
|
||||
};
|
||||
let ty_fn_ptr_from = tcx.coerce_closure_fn_ty(sig);
|
||||
|
||||
if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.at_self()) {
|
||||
span_mirbug!(self, "", "casting {:?}", terr);
|
||||
}
|
||||
}
|
||||
|
||||
CastKind::UnsafeFnPointer => {
|
||||
let ty_fn_ptr_from = tcx.safe_to_unsafe_fn_ty(op.ty(mir, tcx).fn_sig(tcx));
|
||||
|
||||
if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.at_self()) {
|
||||
span_mirbug!(self, "", "casting {:?}", terr);
|
||||
}
|
||||
}
|
||||
|
||||
CastKind::Unsize => {
|
||||
let trait_ref = ty::TraitRef {
|
||||
def_id: tcx.lang_items().coerce_unsized_trait().unwrap(),
|
||||
substs: tcx.mk_substs_trait(op.ty(mir, tcx), &[ty]),
|
||||
};
|
||||
|
||||
self.prove_trait_ref(trait_ref, location);
|
||||
}
|
||||
|
||||
CastKind::Misc => {}
|
||||
}
|
||||
}
|
||||
|
||||
CastKind::ClosureFnPointer => {
|
||||
let sig = match op.ty(mir, tcx).sty {
|
||||
ty::TyClosure(def_id, substs) => {
|
||||
substs.closure_sig_ty(def_id, tcx).fn_sig(tcx)
|
||||
}
|
||||
_ => bug!(),
|
||||
};
|
||||
let ty_fn_ptr_from = tcx.coerce_closure_fn_ty(sig);
|
||||
|
||||
if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.at_self()) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
rvalue,
|
||||
"equating {:?} with {:?} yields {:?}",
|
||||
ty_fn_ptr_from,
|
||||
ty,
|
||||
terr
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
CastKind::UnsafeFnPointer => {
|
||||
let fn_sig = op.ty(mir, tcx).fn_sig(tcx);
|
||||
|
||||
// The type that we see in the fcx is like
|
||||
// `foo::<'a, 'b>`, where `foo` is the path to a
|
||||
// function definition. When we extract the
|
||||
// signature, it comes from the `fn_sig` query,
|
||||
// and hence may contain unnormalized results.
|
||||
let fn_sig = self.normalize(&fn_sig, location);
|
||||
|
||||
let ty_fn_ptr_from = tcx.safe_to_unsafe_fn_ty(fn_sig);
|
||||
|
||||
if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.at_self()) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
rvalue,
|
||||
"equating {:?} with {:?} yields {:?}",
|
||||
ty_fn_ptr_from,
|
||||
ty,
|
||||
terr
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
CastKind::Unsize => {
|
||||
let trait_ref = ty::TraitRef {
|
||||
def_id: tcx.lang_items().coerce_unsized_trait().unwrap(),
|
||||
substs: tcx.mk_substs_trait(op.ty(mir, tcx), &[ty]),
|
||||
};
|
||||
|
||||
self.prove_trait_ref(trait_ref, location);
|
||||
}
|
||||
|
||||
CastKind::Misc => {}
|
||||
},
|
||||
|
||||
// FIXME: These other cases have to be implemented in future PRs
|
||||
Rvalue::Use(..) |
|
||||
@ -1344,8 +1373,7 @@ fn prove_aggregate_predicates(
|
||||
tcx.predicates_of(*def_id).instantiate(tcx, substs.substs)
|
||||
}
|
||||
|
||||
AggregateKind::Array(_) |
|
||||
AggregateKind::Tuple => ty::InstantiatedPredicates::empty(),
|
||||
AggregateKind::Array(_) | AggregateKind::Tuple => ty::InstantiatedPredicates::empty(),
|
||||
};
|
||||
|
||||
let predicates = self.normalize(&instantiated_predicates.predicates, location);
|
||||
|
38
src/test/run-pass/mir-typeck-normalize-fn-sig.rs
Normal file
38
src/test/run-pass/mir-typeck-normalize-fn-sig.rs
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// This code was creating an ICE in the MIR type checker. The reason
|
||||
// is that we are reifying a reference to a function (`foo::<'x>`),
|
||||
// which involves extracting its signature, but we were not
|
||||
// normalizing the signature afterwards. As a result, we sometimes got
|
||||
// errors around the `<u32 as Foo<'x>>::Value`, which can be
|
||||
// normalized to `f64`.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
trait Foo<'x> {
|
||||
type Value;
|
||||
}
|
||||
|
||||
impl<'x> Foo<'x> for u32 {
|
||||
type Value = f64;
|
||||
}
|
||||
|
||||
struct Providers<'x> {
|
||||
foo: for<'y> fn(x: &'x u32, y: &'y u32) -> <u32 as Foo<'x>>::Value,
|
||||
}
|
||||
|
||||
fn foo<'y, 'x: 'x>(x: &'x u32, y: &'y u32) -> <u32 as Foo<'x>>::Value {
|
||||
*x as f64
|
||||
}
|
||||
|
||||
fn main() {
|
||||
Providers { foo };
|
||||
}
|
Loading…
Reference in New Issue
Block a user