Skip to content

Commit e0febe7

Browse files
committed
Auto merge of #45488 - oli-obk:ctfe_resolve, r=eddyb
Resolve types properly in const eval r? @eddyb cc @arielb1
2 parents 56dc171 + 1ee0ff3 commit e0febe7

File tree

3 files changed

+38
-92
lines changed

3 files changed

+38
-92
lines changed

src/librustc/ty/instance.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ impl<'tcx> fmt::Display for Instance<'tcx> {
100100
impl<'a, 'b, 'tcx> Instance<'tcx> {
101101
pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>)
102102
-> Instance<'tcx> {
103-
assert!(substs.is_normalized_for_trans() && !substs.has_escaping_regions(),
103+
assert!(!substs.has_escaping_regions(),
104104
"substs of instance {:?} not normalized for trans: {:?}",
105105
def_id, substs);
106106
Instance { def: InstanceDef::Item(def_id), substs: substs }
@@ -139,7 +139,7 @@ impl<'a, 'b, 'tcx> Instance<'tcx> {
139139
substs: &'tcx Substs<'tcx>) -> Option<Instance<'tcx>> {
140140
debug!("resolve(def_id={:?}, substs={:?})", def_id, substs);
141141
let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) {
142-
debug!(" => associated item, attempting to find impl");
142+
debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env);
143143
let item = tcx.associated_item(def_id);
144144
resolve_associated_item(tcx, &item, param_env, trait_def_id, substs)
145145
} else {

src/librustc_const_eval/eval.rs

+8-90
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@ use rustc::middle::const_val::ConstAggregate::*;
1313
use rustc::middle::const_val::ErrKind::*;
1414
use rustc::middle::const_val::{ByteArray, ConstVal, ConstEvalErr, EvalResult, ErrKind};
1515

16-
use rustc::hir::map as hir_map;
1716
use rustc::hir::map::blocks::FnLikeNode;
18-
use rustc::traits;
1917
use rustc::hir::def::{Def, CtorKind};
2018
use rustc::hir::def_id::DefId;
2119
use rustc::ty::{self, Ty, TyCtxt};
@@ -54,33 +52,12 @@ macro_rules! math {
5452
pub fn lookup_const_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
5553
key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
5654
-> Option<(DefId, &'tcx Substs<'tcx>)> {
57-
let (def_id, _) = key.value;
58-
if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
59-
match tcx.hir.find(node_id) {
60-
Some(hir_map::NodeTraitItem(_)) => {
61-
// If we have a trait item and the substitutions for it,
62-
// `resolve_trait_associated_const` will select an impl
63-
// or the default.
64-
resolve_trait_associated_const(tcx, key)
65-
}
66-
_ => Some(key.value)
67-
}
68-
} else {
69-
match tcx.describe_def(def_id) {
70-
Some(Def::AssociatedConst(_)) => {
71-
// As mentioned in the comments above for in-crate
72-
// constants, we only try to find the expression for a
73-
// trait-associated const if the caller gives us the
74-
// substitutions for the reference to it.
75-
if tcx.trait_of_item(def_id).is_some() {
76-
resolve_trait_associated_const(tcx, key)
77-
} else {
78-
Some(key.value)
79-
}
80-
}
81-
_ => Some(key.value)
82-
}
83-
}
55+
ty::Instance::resolve(
56+
tcx,
57+
key.param_env,
58+
key.value.0,
59+
key.value.1,
60+
).map(|instance| (instance.def_id(), instance.substs))
8461
}
8562

8663
pub struct ConstContext<'a, 'tcx: 'a> {
@@ -119,6 +96,7 @@ type CastResult<'tcx> = Result<ConstVal<'tcx>, ErrKind<'tcx>>;
11996

12097
fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
12198
e: &'tcx Expr) -> EvalResult<'tcx> {
99+
trace!("eval_const_expr_partial: {:?}", e);
122100
let tcx = cx.tcx;
123101
let ty = cx.tables.expr_ty(e).subst(tcx, cx.substs);
124102
let mk_const = |val| tcx.mk_const(ty::Const { val, ty });
@@ -289,6 +267,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
289267
match cx.tables.qpath_def(qpath, e.hir_id) {
290268
Def::Const(def_id) |
291269
Def::AssociatedConst(def_id) => {
270+
let substs = tcx.normalize_associated_type_in_env(&substs, cx.param_env);
292271
match tcx.at(e.span).const_eval(cx.param_env.and((def_id, substs))) {
293272
Ok(val) => val,
294273
Err(ConstEvalErr { kind: TypeckError, .. }) => {
@@ -486,67 +465,6 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
486465
Ok(result)
487466
}
488467

489-
fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
490-
key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
491-
-> Option<(DefId, &'tcx Substs<'tcx>)> {
492-
let param_env = key.param_env;
493-
let (def_id, substs) = key.value;
494-
let trait_item = tcx.associated_item(def_id);
495-
let trait_id = trait_item.container.id();
496-
let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, substs));
497-
debug!("resolve_trait_associated_const: trait_ref={:?}",
498-
trait_ref);
499-
500-
tcx.infer_ctxt().enter(|infcx| {
501-
let mut selcx = traits::SelectionContext::new(&infcx);
502-
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
503-
param_env,
504-
trait_ref.to_poly_trait_predicate());
505-
let selection = match selcx.select(&obligation) {
506-
Ok(Some(vtable)) => vtable,
507-
// Still ambiguous, so give up and let the caller decide whether this
508-
// expression is really needed yet. Some associated constant values
509-
// can't be evaluated until monomorphization is done in trans.
510-
Ok(None) => {
511-
return None
512-
}
513-
Err(_) => {
514-
return None
515-
}
516-
};
517-
518-
// NOTE: this code does not currently account for specialization, but when
519-
// it does so, it should hook into the param_env.reveal to determine when the
520-
// constant should resolve.
521-
match selection {
522-
traits::VtableImpl(ref impl_data) => {
523-
let name = trait_item.name;
524-
let ac = tcx.associated_items(impl_data.impl_def_id)
525-
.find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
526-
match ac {
527-
// FIXME(eddyb) Use proper Instance resolution to
528-
// get the correct Substs returned from here.
529-
Some(ic) => {
530-
let substs = Substs::identity_for_item(tcx, ic.def_id);
531-
Some((ic.def_id, substs))
532-
}
533-
None => {
534-
if trait_item.defaultness.has_value() {
535-
Some(key.value)
536-
} else {
537-
None
538-
}
539-
}
540-
}
541-
}
542-
traits::VtableParam(_) => None,
543-
_ => {
544-
bug!("resolve_trait_associated_const: unexpected vtable type {:?}", selection)
545-
}
546-
}
547-
})
548-
}
549-
550468
fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
551469
val: ConstInt,
552470
ty: Ty<'tcx>)

src/test/run-pass/ctfe/assoc-const.rs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright 2017 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+
trait Nat {
12+
const VALUE: usize;
13+
}
14+
15+
struct Zero;
16+
struct Succ<N>(N);
17+
18+
impl Nat for Zero {
19+
const VALUE: usize = 0;
20+
}
21+
22+
impl<N: Nat> Nat for Succ<N> {
23+
const VALUE: usize = N::VALUE + 1;
24+
}
25+
26+
fn main() {
27+
let x: [i32; <Succ<Succ<Succ<Succ<Zero>>>>>::VALUE] = [1, 2, 3, 4];
28+
}

0 commit comments

Comments
 (0)