From 5efdde0de161a5b374e16e20d09322e5a0eba4f9 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Tue, 22 Mar 2016 17:30:57 +0200 Subject: rustc: move cfg, infer, traits and ty from middle to top-level. --- src/librustc/cfg/construct.rs | 596 ++++ src/librustc/cfg/graphviz.rs | 131 + src/librustc/cfg/mod.rs | 70 + src/librustc/dep_graph/mod.rs | 2 +- src/librustc/infer/README.md | 237 ++ src/librustc/infer/bivariate.rs | 117 + src/librustc/infer/combine.rs | 403 +++ src/librustc/infer/equate.rs | 95 + src/librustc/infer/error_reporting.rs | 2050 +++++++++++++ src/librustc/infer/freshen.rs | 177 ++ src/librustc/infer/glb.rs | 85 + src/librustc/infer/higher_ranked/README.md | 403 +++ src/librustc/infer/higher_ranked/mod.rs | 614 ++++ src/librustc/infer/lattice.rs | 84 + src/librustc/infer/lub.rs | 85 + src/librustc/infer/mod.rs | 1672 +++++++++++ src/librustc/infer/region_inference/README.md | 311 ++ src/librustc/infer/region_inference/graphviz.rs | 273 ++ src/librustc/infer/region_inference/mod.rs | 1453 ++++++++++ src/librustc/infer/resolve.rs | 147 + src/librustc/infer/sub.rs | 116 + src/librustc/infer/type_variable.rs | 324 +++ src/librustc/infer/unify_key.rs | 82 + src/librustc/lib.rs | 12 +- src/librustc/lint/context.rs | 2 +- src/librustc/middle/astconv_util.rs | 2 +- src/librustc/middle/cfg/construct.rs | 596 ---- src/librustc/middle/cfg/graphviz.rs | 131 - src/librustc/middle/cfg/mod.rs | 70 - src/librustc/middle/check_match.rs | 8 +- src/librustc/middle/const_eval.rs | 8 +- src/librustc/middle/cstore.rs | 6 +- src/librustc/middle/dataflow.rs | 6 +- src/librustc/middle/dead.rs | 6 +- src/librustc/middle/def.rs | 2 +- src/librustc/middle/def_id.rs | 2 +- src/librustc/middle/effect.rs | 4 +- src/librustc/middle/expr_use_visitor.rs | 4 +- src/librustc/middle/free_region.rs | 4 +- src/librustc/middle/infer/README.md | 237 -- src/librustc/middle/infer/bivariate.rs | 117 - src/librustc/middle/infer/combine.rs | 403 --- src/librustc/middle/infer/equate.rs | 95 - src/librustc/middle/infer/error_reporting.rs | 2050 ------------- src/librustc/middle/infer/freshen.rs | 177 -- src/librustc/middle/infer/glb.rs | 85 - src/librustc/middle/infer/higher_ranked/README.md | 403 --- src/librustc/middle/infer/higher_ranked/mod.rs | 614 ---- src/librustc/middle/infer/lattice.rs | 84 - src/librustc/middle/infer/lub.rs | 85 - src/librustc/middle/infer/mod.rs | 1672 ----------- .../middle/infer/region_inference/README.md | 311 -- .../middle/infer/region_inference/graphviz.rs | 273 -- src/librustc/middle/infer/region_inference/mod.rs | 1453 ---------- src/librustc/middle/infer/resolve.rs | 147 - src/librustc/middle/infer/sub.rs | 116 - src/librustc/middle/infer/type_variable.rs | 324 --- src/librustc/middle/infer/unify_key.rs | 82 - src/librustc/middle/intrinsicck.rs | 6 +- src/librustc/middle/lang_items.rs | 2 +- src/librustc/middle/liveness.rs | 8 +- src/librustc/middle/mem_categorization.rs | 6 +- src/librustc/middle/pat_util.rs | 2 +- src/librustc/middle/reachable.rs | 2 +- src/librustc/middle/region.rs | 10 +- src/librustc/middle/resolve_lifetime.rs | 4 +- src/librustc/middle/stability.rs | 2 +- src/librustc/middle/traits/README.md | 470 --- src/librustc/middle/traits/coherence.rs | 299 -- src/librustc/middle/traits/error_reporting.rs | 807 ------ src/librustc/middle/traits/fulfill.rs | 764 ----- src/librustc/middle/traits/mod.rs | 623 ---- src/librustc/middle/traits/object_safety.rs | 379 --- src/librustc/middle/traits/project.rs | 1164 -------- src/librustc/middle/traits/select.rs | 3049 -------------------- src/librustc/middle/traits/specialize/mod.rs | 221 -- .../traits/specialize/specialization_graph.rs | 393 --- src/librustc/middle/traits/structural_impls.rs | 256 -- src/librustc/middle/traits/util.rs | 508 ---- src/librustc/middle/ty/_match.rs | 96 - src/librustc/middle/ty/adjustment.rs | 265 -- src/librustc/middle/ty/cast.rs | 76 - src/librustc/middle/ty/contents.rs | 267 -- src/librustc/middle/ty/context.rs | 1081 ------- src/librustc/middle/ty/error.rs | 343 --- src/librustc/middle/ty/fast_reject.rs | 103 - src/librustc/middle/ty/flags.rs | 205 -- src/librustc/middle/ty/fold.rs | 642 ----- src/librustc/middle/ty/item_path.rs | 317 -- src/librustc/middle/ty/ivar.rs | 87 - src/librustc/middle/ty/maps.rs | 45 - src/librustc/middle/ty/mod.rs | 2764 ------------------ src/librustc/middle/ty/outlives.rs | 220 -- src/librustc/middle/ty/relate.rs | 684 ----- src/librustc/middle/ty/structural_impls.rs | 815 ------ src/librustc/middle/ty/sty.rs | 1240 -------- src/librustc/middle/ty/subst.rs | 737 ----- src/librustc/middle/ty/trait_def.rs | 282 -- src/librustc/middle/ty/util.rs | 786 ----- src/librustc/middle/ty/walk.rs | 129 - src/librustc/middle/ty/wf.rs | 509 ---- src/librustc/mir/repr.rs | 4 +- src/librustc/mir/tcx.rs | 6 +- src/librustc/mir/transform.rs | 2 +- src/librustc/mir/visit.rs | 4 +- src/librustc/traits/README.md | 470 +++ src/librustc/traits/coherence.rs | 299 ++ src/librustc/traits/error_reporting.rs | 807 ++++++ src/librustc/traits/fulfill.rs | 764 +++++ src/librustc/traits/mod.rs | 623 ++++ src/librustc/traits/object_safety.rs | 379 +++ src/librustc/traits/project.rs | 1164 ++++++++ src/librustc/traits/select.rs | 3049 ++++++++++++++++++++ src/librustc/traits/specialize/mod.rs | 221 ++ .../traits/specialize/specialization_graph.rs | 393 +++ src/librustc/traits/structural_impls.rs | 256 ++ src/librustc/traits/util.rs | 508 ++++ src/librustc/ty/_match.rs | 96 + src/librustc/ty/adjustment.rs | 265 ++ src/librustc/ty/cast.rs | 76 + src/librustc/ty/contents.rs | 267 ++ src/librustc/ty/context.rs | 1081 +++++++ src/librustc/ty/error.rs | 343 +++ src/librustc/ty/fast_reject.rs | 103 + src/librustc/ty/flags.rs | 205 ++ src/librustc/ty/fold.rs | 642 +++++ src/librustc/ty/item_path.rs | 317 ++ src/librustc/ty/ivar.rs | 87 + src/librustc/ty/maps.rs | 45 + src/librustc/ty/mod.rs | 2764 ++++++++++++++++++ src/librustc/ty/outlives.rs | 220 ++ src/librustc/ty/relate.rs | 684 +++++ src/librustc/ty/structural_impls.rs | 815 ++++++ src/librustc/ty/sty.rs | 1240 ++++++++ src/librustc/ty/subst.rs | 737 +++++ src/librustc/ty/trait_def.rs | 282 ++ src/librustc/ty/util.rs | 786 +++++ src/librustc/ty/walk.rs | 129 + src/librustc/ty/wf.rs | 509 ++++ src/librustc/util/ppaux.rs | 16 +- src/librustc_borrowck/borrowck/check_loans.rs | 6 +- src/librustc_borrowck/borrowck/fragments.rs | 2 +- .../borrowck/gather_loans/gather_moves.rs | 2 +- .../borrowck/gather_loans/lifetime.rs | 2 +- src/librustc_borrowck/borrowck/gather_loans/mod.rs | 6 +- .../borrowck/gather_loans/move_error.rs | 2 +- .../borrowck/gather_loans/restrictions.rs | 2 +- src/librustc_borrowck/borrowck/mir/dataflow.rs | 4 +- src/librustc_borrowck/borrowck/mir/gather_moves.rs | 2 +- src/librustc_borrowck/borrowck/mod.rs | 4 +- src/librustc_borrowck/borrowck/move_data.rs | 4 +- src/librustc_borrowck/graphviz.rs | 6 +- src/librustc_driver/driver.rs | 4 +- src/librustc_driver/pretty.rs | 6 +- src/librustc_driver/test.rs | 30 +- src/librustc_lint/bad_style.rs | 2 +- src/librustc_lint/builtin.rs | 11 +- src/librustc_lint/types.rs | 6 +- src/librustc_lint/unused.rs | 4 +- src/librustc_metadata/astencode.rs | 8 +- src/librustc_metadata/csearch.rs | 2 +- src/librustc_metadata/decoder.rs | 6 +- src/librustc_metadata/encoder.rs | 8 +- src/librustc_metadata/tls_context.rs | 4 +- src/librustc_metadata/tydecode.rs | 6 +- src/librustc_metadata/tyencode.rs | 8 +- src/librustc_mir/build/expr/into.rs | 2 +- src/librustc_mir/build/matches/mod.rs | 2 +- src/librustc_mir/build/matches/test.rs | 2 +- src/librustc_mir/build/misc.rs | 2 +- src/librustc_mir/build/mod.rs | 2 +- src/librustc_mir/build/scope.rs | 4 +- src/librustc_mir/graphviz.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 2 +- src/librustc_mir/hair/cx/mod.rs | 6 +- src/librustc_mir/hair/cx/pattern.rs | 2 +- src/librustc_mir/hair/mod.rs | 4 +- src/librustc_mir/mir_map.rs | 6 +- src/librustc_mir/pretty.rs | 2 +- src/librustc_mir/transform/erase_regions.rs | 4 +- src/librustc_mir/transform/no_landing_pads.rs | 2 +- src/librustc_mir/transform/remove_dead_blocks.rs | 2 +- src/librustc_mir/transform/simplify_cfg.rs | 2 +- src/librustc_mir/transform/type_check.rs | 8 +- src/librustc_passes/consts.rs | 8 +- src/librustc_passes/rvalues.rs | 6 +- src/librustc_platform_intrinsics/aarch64.rs | 2 +- src/librustc_platform_intrinsics/arm.rs | 2 +- src/librustc_platform_intrinsics/lib.rs | 2 +- src/librustc_platform_intrinsics/x86.rs | 2 +- src/librustc_privacy/lib.rs | 2 +- src/librustc_resolve/build_reduced_graph.rs | 2 +- src/librustc_resolve/lib.rs | 4 +- src/librustc_trans/back/symbol_names.rs | 4 +- src/librustc_trans/save/data.rs | 2 +- src/librustc_trans/save/dump_visitor.rs | 2 +- src/librustc_trans/save/mod.rs | 2 +- src/librustc_trans/trans/_match.rs | 8 +- src/librustc_trans/trans/abi.rs | 4 +- src/librustc_trans/trans/adt.rs | 4 +- src/librustc_trans/trans/assert_dep_graph.rs | 2 +- src/librustc_trans/trans/base.rs | 12 +- src/librustc_trans/trans/callee.rs | 10 +- src/librustc_trans/trans/cleanup.rs | 2 +- src/librustc_trans/trans/closure.rs | 6 +- src/librustc_trans/trans/collector.rs | 10 +- src/librustc_trans/trans/common.rs | 12 +- src/librustc_trans/trans/consts.rs | 10 +- src/librustc_trans/trans/context.rs | 6 +- src/librustc_trans/trans/controlflow.rs | 2 +- src/librustc_trans/trans/datum.rs | 2 +- src/librustc_trans/trans/debuginfo/metadata.rs | 6 +- src/librustc_trans/trans/debuginfo/mod.rs | 8 +- src/librustc_trans/trans/debuginfo/type_names.rs | 6 +- src/librustc_trans/trans/declare.rs | 4 +- src/librustc_trans/trans/disr.rs | 4 +- src/librustc_trans/trans/expr.rs | 20 +- src/librustc_trans/trans/glue.rs | 6 +- src/librustc_trans/trans/inline.rs | 2 +- src/librustc_trans/trans/intrinsic.rs | 14 +- src/librustc_trans/trans/meth.rs | 10 +- src/librustc_trans/trans/mir/block.rs | 2 +- src/librustc_trans/trans/mir/constant.rs | 2 +- src/librustc_trans/trans/mir/drop.rs | 2 +- src/librustc_trans/trans/mir/lvalue.rs | 2 +- src/librustc_trans/trans/mir/mod.rs | 2 +- src/librustc_trans/trans/mir/operand.rs | 2 +- src/librustc_trans/trans/mir/rvalue.rs | 4 +- src/librustc_trans/trans/monomorphize.rs | 9 +- src/librustc_trans/trans/symbol_names_test.rs | 2 +- src/librustc_trans/trans/tvec.rs | 2 +- src/librustc_trans/trans/type_of.rs | 10 +- src/librustc_typeck/astconv.rs | 8 +- src/librustc_typeck/check/_match.rs | 6 +- src/librustc_typeck/check/assoc.rs | 6 +- src/librustc_typeck/check/callee.rs | 4 +- src/librustc_typeck/check/cast.rs | 8 +- src/librustc_typeck/check/closure.rs | 4 +- src/librustc_typeck/check/coercion.rs | 20 +- src/librustc_typeck/check/compare_method.rs | 8 +- src/librustc_typeck/check/demand.rs | 4 +- src/librustc_typeck/check/dropck.rs | 8 +- src/librustc_typeck/check/intrinsic.rs | 8 +- src/librustc_typeck/check/method/confirm.rs | 14 +- src/librustc_typeck/check/method/mod.rs | 10 +- src/librustc_typeck/check/method/probe.rs | 12 +- src/librustc_typeck/check/method/suggest.rs | 6 +- src/librustc_typeck/check/mod.rs | 40 +- src/librustc_typeck/check/op.rs | 4 +- src/librustc_typeck/check/regionck.rs | 12 +- src/librustc_typeck/check/upvar.rs | 4 +- src/librustc_typeck/check/wfcheck.rs | 8 +- src/librustc_typeck/check/writeback.rs | 8 +- src/librustc_typeck/coherence/mod.rs | 26 +- src/librustc_typeck/coherence/orphan.rs | 4 +- src/librustc_typeck/coherence/overlap.rs | 6 +- src/librustc_typeck/coherence/unsafety.rs | 2 +- src/librustc_typeck/collect.rs | 12 +- src/librustc_typeck/constrained_type_params.rs | 4 +- src/librustc_typeck/lib.rs | 8 +- src/librustc_typeck/rscope.rs | 2 +- src/librustc_typeck/variance/constraints.rs | 8 +- src/librustc_typeck/variance/mod.rs | 2 +- src/librustc_typeck/variance/solve.rs | 4 +- src/librustc_typeck/variance/terms.rs | 6 +- src/librustc_typeck/variance/xform.rs | 2 +- src/librustdoc/clean/inline.rs | 4 +- src/librustdoc/clean/mod.rs | 6 +- src/librustdoc/clean/simplify.rs | 4 +- src/librustdoc/core.rs | 2 +- src/test/auxiliary/dummy_mir_pass.rs | 2 +- .../moves-based-on-type-cyclic-types-issue-4821.rs | 2 +- src/test/run-make/execution-engine/test.rs | 2 +- 273 files changed, 30603 insertions(+), 30603 deletions(-) create mode 100644 src/librustc/cfg/construct.rs create mode 100644 src/librustc/cfg/graphviz.rs create mode 100644 src/librustc/cfg/mod.rs create mode 100644 src/librustc/infer/README.md create mode 100644 src/librustc/infer/bivariate.rs create mode 100644 src/librustc/infer/combine.rs create mode 100644 src/librustc/infer/equate.rs create mode 100644 src/librustc/infer/error_reporting.rs create mode 100644 src/librustc/infer/freshen.rs create mode 100644 src/librustc/infer/glb.rs create mode 100644 src/librustc/infer/higher_ranked/README.md create mode 100644 src/librustc/infer/higher_ranked/mod.rs create mode 100644 src/librustc/infer/lattice.rs create mode 100644 src/librustc/infer/lub.rs create mode 100644 src/librustc/infer/mod.rs create mode 100644 src/librustc/infer/region_inference/README.md create mode 100644 src/librustc/infer/region_inference/graphviz.rs create mode 100644 src/librustc/infer/region_inference/mod.rs create mode 100644 src/librustc/infer/resolve.rs create mode 100644 src/librustc/infer/sub.rs create mode 100644 src/librustc/infer/type_variable.rs create mode 100644 src/librustc/infer/unify_key.rs delete mode 100644 src/librustc/middle/cfg/construct.rs delete mode 100644 src/librustc/middle/cfg/graphviz.rs delete mode 100644 src/librustc/middle/cfg/mod.rs delete mode 100644 src/librustc/middle/infer/README.md delete mode 100644 src/librustc/middle/infer/bivariate.rs delete mode 100644 src/librustc/middle/infer/combine.rs delete mode 100644 src/librustc/middle/infer/equate.rs delete mode 100644 src/librustc/middle/infer/error_reporting.rs delete mode 100644 src/librustc/middle/infer/freshen.rs delete mode 100644 src/librustc/middle/infer/glb.rs delete mode 100644 src/librustc/middle/infer/higher_ranked/README.md delete mode 100644 src/librustc/middle/infer/higher_ranked/mod.rs delete mode 100644 src/librustc/middle/infer/lattice.rs delete mode 100644 src/librustc/middle/infer/lub.rs delete mode 100644 src/librustc/middle/infer/mod.rs delete mode 100644 src/librustc/middle/infer/region_inference/README.md delete mode 100644 src/librustc/middle/infer/region_inference/graphviz.rs delete mode 100644 src/librustc/middle/infer/region_inference/mod.rs delete mode 100644 src/librustc/middle/infer/resolve.rs delete mode 100644 src/librustc/middle/infer/sub.rs delete mode 100644 src/librustc/middle/infer/type_variable.rs delete mode 100644 src/librustc/middle/infer/unify_key.rs delete mode 100644 src/librustc/middle/traits/README.md delete mode 100644 src/librustc/middle/traits/coherence.rs delete mode 100644 src/librustc/middle/traits/error_reporting.rs delete mode 100644 src/librustc/middle/traits/fulfill.rs delete mode 100644 src/librustc/middle/traits/mod.rs delete mode 100644 src/librustc/middle/traits/object_safety.rs delete mode 100644 src/librustc/middle/traits/project.rs delete mode 100644 src/librustc/middle/traits/select.rs delete mode 100644 src/librustc/middle/traits/specialize/mod.rs delete mode 100644 src/librustc/middle/traits/specialize/specialization_graph.rs delete mode 100644 src/librustc/middle/traits/structural_impls.rs delete mode 100644 src/librustc/middle/traits/util.rs delete mode 100644 src/librustc/middle/ty/_match.rs delete mode 100644 src/librustc/middle/ty/adjustment.rs delete mode 100644 src/librustc/middle/ty/cast.rs delete mode 100644 src/librustc/middle/ty/contents.rs delete mode 100644 src/librustc/middle/ty/context.rs delete mode 100644 src/librustc/middle/ty/error.rs delete mode 100644 src/librustc/middle/ty/fast_reject.rs delete mode 100644 src/librustc/middle/ty/flags.rs delete mode 100644 src/librustc/middle/ty/fold.rs delete mode 100644 src/librustc/middle/ty/item_path.rs delete mode 100644 src/librustc/middle/ty/ivar.rs delete mode 100644 src/librustc/middle/ty/maps.rs delete mode 100644 src/librustc/middle/ty/mod.rs delete mode 100644 src/librustc/middle/ty/outlives.rs delete mode 100644 src/librustc/middle/ty/relate.rs delete mode 100644 src/librustc/middle/ty/structural_impls.rs delete mode 100644 src/librustc/middle/ty/sty.rs delete mode 100644 src/librustc/middle/ty/subst.rs delete mode 100644 src/librustc/middle/ty/trait_def.rs delete mode 100644 src/librustc/middle/ty/util.rs delete mode 100644 src/librustc/middle/ty/walk.rs delete mode 100644 src/librustc/middle/ty/wf.rs create mode 100644 src/librustc/traits/README.md create mode 100644 src/librustc/traits/coherence.rs create mode 100644 src/librustc/traits/error_reporting.rs create mode 100644 src/librustc/traits/fulfill.rs create mode 100644 src/librustc/traits/mod.rs create mode 100644 src/librustc/traits/object_safety.rs create mode 100644 src/librustc/traits/project.rs create mode 100644 src/librustc/traits/select.rs create mode 100644 src/librustc/traits/specialize/mod.rs create mode 100644 src/librustc/traits/specialize/specialization_graph.rs create mode 100644 src/librustc/traits/structural_impls.rs create mode 100644 src/librustc/traits/util.rs create mode 100644 src/librustc/ty/_match.rs create mode 100644 src/librustc/ty/adjustment.rs create mode 100644 src/librustc/ty/cast.rs create mode 100644 src/librustc/ty/contents.rs create mode 100644 src/librustc/ty/context.rs create mode 100644 src/librustc/ty/error.rs create mode 100644 src/librustc/ty/fast_reject.rs create mode 100644 src/librustc/ty/flags.rs create mode 100644 src/librustc/ty/fold.rs create mode 100644 src/librustc/ty/item_path.rs create mode 100644 src/librustc/ty/ivar.rs create mode 100644 src/librustc/ty/maps.rs create mode 100644 src/librustc/ty/mod.rs create mode 100644 src/librustc/ty/outlives.rs create mode 100644 src/librustc/ty/relate.rs create mode 100644 src/librustc/ty/structural_impls.rs create mode 100644 src/librustc/ty/sty.rs create mode 100644 src/librustc/ty/subst.rs create mode 100644 src/librustc/ty/trait_def.rs create mode 100644 src/librustc/ty/util.rs create mode 100644 src/librustc/ty/walk.rs create mode 100644 src/librustc/ty/wf.rs (limited to 'src') diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs new file mode 100644 index 00000000000..e75625f7fae --- /dev/null +++ b/src/librustc/cfg/construct.rs @@ -0,0 +1,596 @@ +// Copyright 2012-2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc_data_structures::graph; +use cfg::*; +use middle::def::Def; +use middle::pat_util; +use ty::{self, TyCtxt}; +use syntax::ast; +use syntax::ptr::P; + +use rustc_front::hir::{self, PatKind}; + +struct CFGBuilder<'a, 'tcx: 'a> { + tcx: &'a TyCtxt<'tcx>, + graph: CFGGraph, + fn_exit: CFGIndex, + loop_scopes: Vec, +} + +#[derive(Copy, Clone)] +struct LoopScope { + loop_id: ast::NodeId, // id of loop/while node + continue_index: CFGIndex, // where to go on a `loop` + break_index: CFGIndex, // where to go on a `break +} + +pub fn construct(tcx: &TyCtxt, + blk: &hir::Block) -> CFG { + let mut graph = graph::Graph::new(); + let entry = graph.add_node(CFGNodeData::Entry); + + // `fn_exit` is target of return exprs, which lies somewhere + // outside input `blk`. (Distinguishing `fn_exit` and `block_exit` + // also resolves chicken-and-egg problem that arises if you try to + // have return exprs jump to `block_exit` during construction.) + let fn_exit = graph.add_node(CFGNodeData::Exit); + let block_exit; + + let mut cfg_builder = CFGBuilder { + graph: graph, + fn_exit: fn_exit, + tcx: tcx, + loop_scopes: Vec::new() + }; + block_exit = cfg_builder.block(blk, entry); + cfg_builder.add_contained_edge(block_exit, fn_exit); + let CFGBuilder {graph, ..} = cfg_builder; + CFG {graph: graph, + entry: entry, + exit: fn_exit} +} + +impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { + fn block(&mut self, blk: &hir::Block, pred: CFGIndex) -> CFGIndex { + let mut stmts_exit = pred; + for stmt in &blk.stmts { + stmts_exit = self.stmt(stmt, stmts_exit); + } + + let expr_exit = self.opt_expr(&blk.expr, stmts_exit); + + self.add_ast_node(blk.id, &[expr_exit]) + } + + fn stmt(&mut self, stmt: &hir::Stmt, pred: CFGIndex) -> CFGIndex { + match stmt.node { + hir::StmtDecl(ref decl, id) => { + let exit = self.decl(&decl, pred); + self.add_ast_node(id, &[exit]) + } + + hir::StmtExpr(ref expr, id) | hir::StmtSemi(ref expr, id) => { + let exit = self.expr(&expr, pred); + self.add_ast_node(id, &[exit]) + } + } + } + + fn decl(&mut self, decl: &hir::Decl, pred: CFGIndex) -> CFGIndex { + match decl.node { + hir::DeclLocal(ref local) => { + let init_exit = self.opt_expr(&local.init, pred); + self.pat(&local.pat, init_exit) + } + + hir::DeclItem(_) => { + pred + } + } + } + + fn pat(&mut self, pat: &hir::Pat, pred: CFGIndex) -> CFGIndex { + match pat.node { + PatKind::Ident(_, _, None) | + PatKind::TupleStruct(_, None) | + PatKind::Path(..) | + PatKind::QPath(..) | + PatKind::Lit(..) | + PatKind::Range(..) | + PatKind::Wild => { + self.add_ast_node(pat.id, &[pred]) + } + + PatKind::Box(ref subpat) | + PatKind::Ref(ref subpat, _) | + PatKind::Ident(_, _, Some(ref subpat)) => { + let subpat_exit = self.pat(&subpat, pred); + self.add_ast_node(pat.id, &[subpat_exit]) + } + + PatKind::TupleStruct(_, Some(ref subpats)) | + PatKind::Tup(ref subpats) => { + let pats_exit = self.pats_all(subpats.iter(), pred); + self.add_ast_node(pat.id, &[pats_exit]) + } + + PatKind::Struct(_, ref subpats, _) => { + let pats_exit = + self.pats_all(subpats.iter().map(|f| &f.node.pat), pred); + self.add_ast_node(pat.id, &[pats_exit]) + } + + PatKind::Vec(ref pre, ref vec, ref post) => { + let pre_exit = self.pats_all(pre.iter(), pred); + let vec_exit = self.pats_all(vec.iter(), pre_exit); + let post_exit = self.pats_all(post.iter(), vec_exit); + self.add_ast_node(pat.id, &[post_exit]) + } + } + } + + fn pats_all<'b, I: Iterator>>(&mut self, + pats: I, + pred: CFGIndex) -> CFGIndex { + //! Handles case where all of the patterns must match. + pats.fold(pred, |pred, pat| self.pat(&pat, pred)) + } + + fn expr(&mut self, expr: &hir::Expr, pred: CFGIndex) -> CFGIndex { + match expr.node { + hir::ExprBlock(ref blk) => { + let blk_exit = self.block(&blk, pred); + self.add_ast_node(expr.id, &[blk_exit]) + } + + hir::ExprIf(ref cond, ref then, None) => { + // + // [pred] + // | + // v 1 + // [cond] + // | + // / \ + // / \ + // v 2 * + // [then] | + // | | + // v 3 v 4 + // [..expr..] + // + let cond_exit = self.expr(&cond, pred); // 1 + let then_exit = self.block(&then, cond_exit); // 2 + self.add_ast_node(expr.id, &[cond_exit, then_exit]) // 3,4 + } + + hir::ExprIf(ref cond, ref then, Some(ref otherwise)) => { + // + // [pred] + // | + // v 1 + // [cond] + // | + // / \ + // / \ + // v 2 v 3 + // [then][otherwise] + // | | + // v 4 v 5 + // [..expr..] + // + let cond_exit = self.expr(&cond, pred); // 1 + let then_exit = self.block(&then, cond_exit); // 2 + let else_exit = self.expr(&otherwise, cond_exit); // 3 + self.add_ast_node(expr.id, &[then_exit, else_exit]) // 4, 5 + } + + hir::ExprWhile(ref cond, ref body, _) => { + // + // [pred] + // | + // v 1 + // [loopback] <--+ 5 + // | | + // v 2 | + // +-----[cond] | + // | | | + // | v 4 | + // | [body] -----+ + // v 3 + // [expr] + // + // Note that `break` and `continue` statements + // may cause additional edges. + + // Is the condition considered part of the loop? + let loopback = self.add_dummy_node(&[pred]); // 1 + let cond_exit = self.expr(&cond, loopback); // 2 + let expr_exit = self.add_ast_node(expr.id, &[cond_exit]); // 3 + self.loop_scopes.push(LoopScope { + loop_id: expr.id, + continue_index: loopback, + break_index: expr_exit + }); + let body_exit = self.block(&body, cond_exit); // 4 + self.add_contained_edge(body_exit, loopback); // 5 + self.loop_scopes.pop(); + expr_exit + } + + hir::ExprLoop(ref body, _) => { + // + // [pred] + // | + // v 1 + // [loopback] <---+ + // | 4 | + // v 3 | + // [body] ------+ + // + // [expr] 2 + // + // Note that `break` and `loop` statements + // may cause additional edges. + + let loopback = self.add_dummy_node(&[pred]); // 1 + let expr_exit = self.add_ast_node(expr.id, &[]); // 2 + self.loop_scopes.push(LoopScope { + loop_id: expr.id, + continue_index: loopback, + break_index: expr_exit, + }); + let body_exit = self.block(&body, loopback); // 3 + self.add_contained_edge(body_exit, loopback); // 4 + self.loop_scopes.pop(); + expr_exit + } + + hir::ExprMatch(ref discr, ref arms, _) => { + self.match_(expr.id, &discr, &arms, pred) + } + + hir::ExprBinary(op, ref l, ref r) if ::rustc_front::util::lazy_binop(op.node) => { + // + // [pred] + // | + // v 1 + // [l] + // | + // / \ + // / \ + // v 2 * + // [r] | + // | | + // v 3 v 4 + // [..exit..] + // + let l_exit = self.expr(&l, pred); // 1 + let r_exit = self.expr(&r, l_exit); // 2 + self.add_ast_node(expr.id, &[l_exit, r_exit]) // 3,4 + } + + hir::ExprRet(ref v) => { + let v_exit = self.opt_expr(v, pred); + let b = self.add_ast_node(expr.id, &[v_exit]); + self.add_returning_edge(expr, b); + self.add_unreachable_node() + } + + hir::ExprBreak(label) => { + let loop_scope = self.find_scope(expr, label.map(|l| l.node.name)); + let b = self.add_ast_node(expr.id, &[pred]); + self.add_exiting_edge(expr, b, + loop_scope, loop_scope.break_index); + self.add_unreachable_node() + } + + hir::ExprAgain(label) => { + let loop_scope = self.find_scope(expr, label.map(|l| l.node.name)); + let a = self.add_ast_node(expr.id, &[pred]); + self.add_exiting_edge(expr, a, + loop_scope, loop_scope.continue_index); + self.add_unreachable_node() + } + + hir::ExprVec(ref elems) => { + self.straightline(expr, pred, elems.iter().map(|e| &**e)) + } + + hir::ExprCall(ref func, ref args) => { + self.call(expr, pred, &func, args.iter().map(|e| &**e)) + } + + hir::ExprMethodCall(_, _, ref args) => { + self.call(expr, pred, &args[0], args[1..].iter().map(|e| &**e)) + } + + hir::ExprIndex(ref l, ref r) | + hir::ExprBinary(_, ref l, ref r) if self.tcx.is_method_call(expr.id) => { + self.call(expr, pred, &l, Some(&**r).into_iter()) + } + + hir::ExprUnary(_, ref e) if self.tcx.is_method_call(expr.id) => { + self.call(expr, pred, &e, None::.iter()) + } + + hir::ExprTup(ref exprs) => { + self.straightline(expr, pred, exprs.iter().map(|e| &**e)) + } + + hir::ExprStruct(_, ref fields, ref base) => { + let field_cfg = self.straightline(expr, pred, fields.iter().map(|f| &*f.expr)); + self.opt_expr(base, field_cfg) + } + + hir::ExprRepeat(ref elem, ref count) => { + self.straightline(expr, pred, [elem, count].iter().map(|&e| &**e)) + } + + hir::ExprAssign(ref l, ref r) | + hir::ExprAssignOp(_, ref l, ref r) => { + self.straightline(expr, pred, [r, l].iter().map(|&e| &**e)) + } + + hir::ExprIndex(ref l, ref r) | + hir::ExprBinary(_, ref l, ref r) => { // NB: && and || handled earlier + self.straightline(expr, pred, [l, r].iter().map(|&e| &**e)) + } + + hir::ExprBox(ref e) | + hir::ExprAddrOf(_, ref e) | + hir::ExprCast(ref e, _) | + hir::ExprType(ref e, _) | + hir::ExprUnary(_, ref e) | + hir::ExprField(ref e, _) | + hir::ExprTupField(ref e, _) => { + self.straightline(expr, pred, Some(&**e).into_iter()) + } + + hir::ExprInlineAsm(_, ref outputs, ref inputs) => { + let post_outputs = self.exprs(outputs.iter().map(|e| &**e), pred); + let post_inputs = self.exprs(inputs.iter().map(|e| &**e), post_outputs); + self.add_ast_node(expr.id, &[post_inputs]) + } + + hir::ExprClosure(..) | + hir::ExprLit(..) | + hir::ExprPath(..) => { + self.straightline(expr, pred, None::.iter()) + } + } + } + + fn call<'b, I: Iterator>(&mut self, + call_expr: &hir::Expr, + pred: CFGIndex, + func_or_rcvr: &hir::Expr, + args: I) -> CFGIndex { + let method_call = ty::MethodCall::expr(call_expr.id); + let fn_ty = match self.tcx.tables.borrow().method_map.get(&method_call) { + Some(method) => method.ty, + None => self.tcx.expr_ty_adjusted(func_or_rcvr) + }; + + let func_or_rcvr_exit = self.expr(func_or_rcvr, pred); + let ret = self.straightline(call_expr, func_or_rcvr_exit, args); + if fn_ty.fn_ret().diverges() { + self.add_unreachable_node() + } else { + ret + } + } + + fn exprs<'b, I: Iterator>(&mut self, + exprs: I, + pred: CFGIndex) -> CFGIndex { + //! Constructs graph for `exprs` evaluated in order + exprs.fold(pred, |p, e| self.expr(e, p)) + } + + fn opt_expr(&mut self, + opt_expr: &Option>, + pred: CFGIndex) -> CFGIndex { + //! Constructs graph for `opt_expr` evaluated, if Some + opt_expr.iter().fold(pred, |p, e| self.expr(&e, p)) + } + + fn straightline<'b, I: Iterator>(&mut self, + expr: &hir::Expr, + pred: CFGIndex, + subexprs: I) -> CFGIndex { + //! Handles case of an expression that evaluates `subexprs` in order + + let subexprs_exit = self.exprs(subexprs, pred); + self.add_ast_node(expr.id, &[subexprs_exit]) + } + + fn match_(&mut self, id: ast::NodeId, discr: &hir::Expr, + arms: &[hir::Arm], pred: CFGIndex) -> CFGIndex { + // The CFG for match expression is quite complex, so no ASCII + // art for it (yet). + // + // The CFG generated below matches roughly what trans puts + // out. Each pattern and guard is visited in parallel, with + // arms containing multiple patterns generating multiple nodes + // for the same guard expression. The guard expressions chain + // into each other from top to bottom, with a specific + // exception to allow some additional valid programs + // (explained below). Trans differs slightly in that the + // pattern matching may continue after a guard but the visible + // behaviour should be the same. + // + // What is going on is explained in further comments. + + // Visit the discriminant expression + let discr_exit = self.expr(discr, pred); + + // Add a node for the exit of the match expression as a whole. + let expr_exit = self.add_ast_node(id, &[]); + + // Keep track of the previous guard expressions + let mut prev_guards = Vec::new(); + // Track if the previous pattern contained bindings or wildcards + let mut prev_has_bindings = false; + + for arm in arms { + // Add an exit node for when we've visited all the + // patterns and the guard (if there is one) in the arm. + let arm_exit = self.add_dummy_node(&[]); + + for pat in &arm.pats { + // Visit the pattern, coming from the discriminant exit + let mut pat_exit = self.pat(&pat, discr_exit); + + // If there is a guard expression, handle it here + if let Some(ref guard) = arm.guard { + // Add a dummy node for the previous guard + // expression to target + let guard_start = self.add_dummy_node(&[pat_exit]); + // Visit the guard expression + let guard_exit = self.expr(&guard, guard_start); + + let this_has_bindings = pat_util::pat_contains_bindings_or_wild( + &self.tcx.def_map.borrow(), &pat); + + // If both this pattern and the previous pattern + // were free of bindings, they must consist only + // of "constant" patterns. Note we cannot match an + // all-constant pattern, fail the guard, and then + // match *another* all-constant pattern. This is + // because if the previous pattern matches, then + // we *cannot* match this one, unless all the + // constants are the same (which is rejected by + // `check_match`). + // + // We can use this to be smarter about the flow + // along guards. If the previous pattern matched, + // then we know we will not visit the guard in + // this one (whether or not the guard succeeded), + // if the previous pattern failed, then we know + // the guard for that pattern will not have been + // visited. Thus, it is not possible to visit both + // the previous guard and the current one when + // both patterns consist only of constant + // sub-patterns. + // + // However, if the above does not hold, then all + // previous guards need to be wired to visit the + // current guard pattern. + if prev_has_bindings || this_has_bindings { + while let Some(prev) = prev_guards.pop() { + self.add_contained_edge(prev, guard_start); + } + } + + prev_has_bindings = this_has_bindings; + + // Push the guard onto the list of previous guards + prev_guards.push(guard_exit); + + // Update the exit node for the pattern + pat_exit = guard_exit; + } + + // Add an edge from the exit of this pattern to the + // exit of the arm + self.add_contained_edge(pat_exit, arm_exit); + } + + // Visit the body of this arm + let body_exit = self.expr(&arm.body, arm_exit); + + // Link the body to the exit of the expression + self.add_contained_edge(body_exit, expr_exit); + } + + expr_exit + } + + fn add_dummy_node(&mut self, preds: &[CFGIndex]) -> CFGIndex { + self.add_node(CFGNodeData::Dummy, preds) + } + + fn add_ast_node(&mut self, id: ast::NodeId, preds: &[CFGIndex]) -> CFGIndex { + assert!(id != ast::DUMMY_NODE_ID); + self.add_node(CFGNodeData::AST(id), preds) + } + + fn add_unreachable_node(&mut self) -> CFGIndex { + self.add_node(CFGNodeData::Unreachable, &[]) + } + + fn add_node(&mut self, data: CFGNodeData, preds: &[CFGIndex]) -> CFGIndex { + let node = self.graph.add_node(data); + for &pred in preds { + self.add_contained_edge(pred, node); + } + node + } + + fn add_contained_edge(&mut self, + source: CFGIndex, + target: CFGIndex) { + let data = CFGEdgeData {exiting_scopes: vec!() }; + self.graph.add_edge(source, target, data); + } + + fn add_exiting_edge(&mut self, + from_expr: &hir::Expr, + from_index: CFGIndex, + to_loop: LoopScope, + to_index: CFGIndex) { + let mut data = CFGEdgeData {exiting_scopes: vec!() }; + let mut scope = self.tcx.region_maps.node_extent(from_expr.id); + let target_scope = self.tcx.region_maps.node_extent(to_loop.loop_id); + while scope != target_scope { + data.exiting_scopes.push(scope.node_id(&self.tcx.region_maps)); + scope = self.tcx.region_maps.encl_scope(scope); + } + self.graph.add_edge(from_index, to_index, data); + } + + fn add_returning_edge(&mut self, + _from_expr: &hir::Expr, + from_index: CFGIndex) { + let mut data = CFGEdgeData { + exiting_scopes: vec!(), + }; + for &LoopScope { loop_id: id, .. } in self.loop_scopes.iter().rev() { + data.exiting_scopes.push(id); + } + self.graph.add_edge(from_index, self.fn_exit, data); + } + + fn find_scope(&self, + expr: &hir::Expr, + label: Option) -> LoopScope { + if label.is_none() { + return *self.loop_scopes.last().unwrap(); + } + + match self.tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def()) { + Some(Def::Label(loop_id)) => { + for l in &self.loop_scopes { + if l.loop_id == loop_id { + return *l; + } + } + self.tcx.sess.span_bug(expr.span, + &format!("no loop scope for id {}", loop_id)); + } + + r => { + self.tcx.sess.span_bug(expr.span, + &format!("bad entry `{:?}` in def_map for label", r)); + } + } + } +} diff --git a/src/librustc/cfg/graphviz.rs b/src/librustc/cfg/graphviz.rs new file mode 100644 index 00000000000..c867ec94b25 --- /dev/null +++ b/src/librustc/cfg/graphviz.rs @@ -0,0 +1,131 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// This module provides linkage between rustc::middle::graph and +/// libgraphviz traits. + +// For clarity, rename the graphviz crate locally to dot. +use graphviz as dot; +use graphviz::IntoCow; + +use syntax::ast; + +use front::map as ast_map; +use cfg; + +pub type Node<'a> = (cfg::CFGIndex, &'a cfg::CFGNode); +pub type Edge<'a> = &'a cfg::CFGEdge; + +pub struct LabelledCFG<'a, 'ast: 'a> { + pub ast_map: &'a ast_map::Map<'ast>, + pub cfg: &'a cfg::CFG, + pub name: String, + /// `labelled_edges` controls whether we emit labels on the edges + pub labelled_edges: bool, +} + +fn replace_newline_with_backslash_l(s: String) -> String { + // Replacing newlines with \\l causes each line to be left-aligned, + // improving presentation of (long) pretty-printed expressions. + if s.contains("\n") { + let mut s = s.replace("\n", "\\l"); + // Apparently left-alignment applies to the line that precedes + // \l, not the line that follows; so, add \l at end of string + // if not already present, ensuring last line gets left-aligned + // as well. + let mut last_two: Vec<_> = + s.chars().rev().take(2).collect(); + last_two.reverse(); + if last_two != ['\\', 'l'] { + s.push_str("\\l"); + } + s + } else { + s + } +} + +impl<'a, 'ast> dot::Labeller<'a> for LabelledCFG<'a, 'ast> { + type Node = Node<'a>; + type Edge = Edge<'a>; + fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new(&self.name[..]).unwrap() } + + fn node_id(&'a self, &(i,_): &Node<'a>) -> dot::Id<'a> { + dot::Id::new(format!("N{}", i.node_id())).unwrap() + } + + fn node_label(&'a self, &(i, n): &Node<'a>) -> dot::LabelText<'a> { + if i == self.cfg.entry { + dot::LabelText::LabelStr("entry".into_cow()) + } else if i == self.cfg.exit { + dot::LabelText::LabelStr("exit".into_cow()) + } else if n.data.id() == ast::DUMMY_NODE_ID { + dot::LabelText::LabelStr("(dummy_node)".into_cow()) + } else { + let s = self.ast_map.node_to_string(n.data.id()); + // left-aligns the lines + let s = replace_newline_with_backslash_l(s); + dot::LabelText::EscStr(s.into_cow()) + } + } + + fn edge_label(&self, e: &Edge<'a>) -> dot::LabelText<'a> { + let mut label = String::new(); + if !self.labelled_edges { + return dot::LabelText::EscStr(label.into_cow()); + } + let mut put_one = false; + for (i, &node_id) in e.data.exiting_scopes.iter().enumerate() { + if put_one { + label.push_str(",\\l"); + } else { + put_one = true; + } + let s = self.ast_map.node_to_string(node_id); + // left-aligns the lines + let s = replace_newline_with_backslash_l(s); + label.push_str(&format!("exiting scope_{} {}", + i, + &s[..])); + } + dot::LabelText::EscStr(label.into_cow()) + } +} + +impl<'a> dot::GraphWalk<'a> for &'a cfg::CFG { + type Node = Node<'a>; + type Edge = Edge<'a>; + fn nodes(&'a self) -> dot::Nodes<'a, Node<'a>> { + let mut v = Vec::new(); + self.graph.each_node(|i, nd| { v.push((i, nd)); true }); + v.into_cow() + } + fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> { + self.graph.all_edges().iter().collect() + } + fn source(&'a self, edge: &Edge<'a>) -> Node<'a> { + let i = edge.source(); + (i, self.graph.node(i)) + } + fn target(&'a self, edge: &Edge<'a>) -> Node<'a> { + let i = edge.target(); + (i, self.graph.node(i)) + } +} + +impl<'a, 'ast> dot::GraphWalk<'a> for LabelledCFG<'a, 'ast> +{ + type Node = Node<'a>; + type Edge = Edge<'a>; + fn nodes(&'a self) -> dot::Nodes<'a, Node<'a>> { self.cfg.nodes() } + fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> { self.cfg.edges() } + fn source(&'a self, edge: &Edge<'a>) -> Node<'a> { self.cfg.source(edge) } + fn target(&'a self, edge: &Edge<'a>) -> Node<'a> { self.cfg.target(edge) } +} diff --git a/src/librustc/cfg/mod.rs b/src/librustc/cfg/mod.rs new file mode 100644 index 00000000000..8df4dc5fce5 --- /dev/null +++ b/src/librustc/cfg/mod.rs @@ -0,0 +1,70 @@ +// Copyright 2012 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Module that constructs a control-flow graph representing an item. +//! Uses `Graph` as the underlying representation. + +use rustc_data_structures::graph; +use ty::TyCtxt; +use syntax::ast; +use rustc_front::hir; + +mod construct; +pub mod graphviz; + +pub struct CFG { + pub graph: CFGGraph, + pub entry: CFGIndex, + pub exit: CFGIndex, +} + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum CFGNodeData { + AST(ast::NodeId), + Entry, + Exit, + Dummy, + Unreachable, +} + +impl CFGNodeData { + pub fn id(&self) -> ast::NodeId { + if let CFGNodeData::AST(id) = *self { + id + } else { + ast::DUMMY_NODE_ID + } + } +} + +#[derive(Debug)] +pub struct CFGEdgeData { + pub exiting_scopes: Vec +} + +pub type CFGIndex = graph::NodeIndex; + +pub type CFGGraph = graph::Graph; + +pub type CFGNode = graph::Node; + +pub type CFGEdge = graph::Edge; + +impl CFG { + pub fn new(tcx: &TyCtxt, + blk: &hir::Block) -> CFG { + construct::construct(tcx, blk) + } + + pub fn node_is_reachable(&self, id: ast::NodeId) -> bool { + self.graph.depth_traverse(self.entry) + .any(|idx| self.graph.node_data(idx).id() == id) + } +} diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 821217d7582..731c33868df 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -11,7 +11,7 @@ use self::thread::{DepGraphThreadData, DepMessage}; use middle::def_id::DefId; use syntax::ast::NodeId; -use middle::ty::TyCtxt; +use ty::TyCtxt; use rustc_front::hir; use rustc_front::intravisit::Visitor; use std::rc::Rc; diff --git a/src/librustc/infer/README.md b/src/librustc/infer/README.md new file mode 100644 index 00000000000..c835189820e --- /dev/null +++ b/src/librustc/infer/README.md @@ -0,0 +1,237 @@ +# Type inference engine + +This is loosely based on standard HM-type inference, but with an +extension to try and accommodate subtyping. There is nothing +principled about this extension; it's sound---I hope!---but it's a +heuristic, ultimately, and does not guarantee that it finds a valid +typing even if one exists (in fact, there are known scenarios where it +fails, some of which may eventually become problematic). + +## Key idea + +The main change is that each type variable T is associated with a +lower-bound L and an upper-bound U. L and U begin as bottom and top, +respectively, but gradually narrow in response to new constraints +being introduced. When a variable is finally resolved to a concrete +type, it can (theoretically) select any type that is a supertype of L +and a subtype of U. + +There are several critical invariants which we maintain: + +- the upper-bound of a variable only becomes lower and the lower-bound + only becomes higher over time; +- the lower-bound L is always a subtype of the upper bound U; +- the lower-bound L and upper-bound U never refer to other type variables, + but only to types (though those types may contain type variables). + +> An aside: if the terms upper- and lower-bound confuse you, think of +> "supertype" and "subtype". The upper-bound is a "supertype" +> (super=upper in Latin, or something like that anyway) and the lower-bound +> is a "subtype" (sub=lower in Latin). I find it helps to visualize +> a simple class hierarchy, like Java minus interfaces and +> primitive types. The class Object is at the root (top) and other +> types lie in between. The bottom type is then the Null type. +> So the tree looks like: +> +> ```text +> Object +> / \ +> String Other +> \ / +> (null) +> ``` +> +> So the upper bound type is the "supertype" and the lower bound is the +> "subtype" (also, super and sub mean upper and lower in Latin, or something +> like that anyway). + +## Satisfying constraints + +At a primitive level, there is only one form of constraint that the +inference understands: a subtype relation. So the outside world can +say "make type A a subtype of type B". If there are variables +involved, the inferencer will adjust their upper- and lower-bounds as +needed to ensure that this relation is satisfied. (We also allow "make +type A equal to type B", but this is translated into "A <: B" and "B +<: A") + +As stated above, we always maintain the invariant that type bounds +never refer to other variables. This keeps the inference relatively +simple, avoiding the scenario of having a kind of graph where we have +to pump constraints along and reach a fixed point, but it does impose +some heuristics in the case where the user is relating two type +variables A <: B. + +Combining two variables such that variable A will forever be a subtype +of variable B is the trickiest part of the algorithm because there is +often no right choice---that is, the right choice will depend on +future constraints which we do not yet know. The problem comes about +because both A and B have bounds that can be adjusted in the future. +Let's look at some of the cases that can come up. + +Imagine, to start, the best case, where both A and B have an upper and +lower bound (that is, the bounds are not top nor bot respectively). In +that case, if we're lucky, A.ub <: B.lb, and so we know that whatever +A and B should become, they will forever have the desired subtyping +relation. We can just leave things as they are. + +### Option 1: Unify + +However, suppose that A.ub is *not* a subtype of B.lb. In +that case, we must make a decision. One option is to unify A +and B so that they are one variable whose bounds are: + + UB = GLB(A.ub, B.ub) + LB = LUB(A.lb, B.lb) + +(Note that we will have to verify that LB <: UB; if it does not, the +types are not intersecting and there is an error) In that case, A <: B +holds trivially because A==B. However, we have now lost some +flexibility, because perhaps the user intended for A and B to end up +as different types and not the same type. + +Pictorally, what this does is to take two distinct variables with +(hopefully not completely) distinct type ranges and produce one with +the intersection. + +```text + B.ub B.ub + /\ / + A.ub / \ A.ub / + / \ / \ \ / + / X \ UB + / / \ \ / \ + / / / \ / / + \ \ / / \ / + \ X / LB + \ / \ / / \ + \ / \ / / \ + A.lb B.lb A.lb B.lb +``` + + +### Option 2: Relate UB/LB + +Another option is to keep A and B as distinct variables but set their +bounds in such a way that, whatever happens, we know that A <: B will hold. +This can be achieved by ensuring that A.ub <: B.lb. In practice there +are two ways to do that, depicted pictorially here: + +```text + Before Option #1 Option #2 + + B.ub B.ub B.ub + /\ / \ / \ + A.ub / \ A.ub /(B')\ A.ub /(B')\ + / \ / \ \ / / \ / / + / X \ __UB____/ UB / + / / \ \ / | | / + / / / \ / | | / + \ \ / / /(A')| | / + \ X / / LB ______LB/ + \ / \ / / / \ / (A')/ \ + \ / \ / \ / \ \ / \ + A.lb B.lb A.lb B.lb A.lb B.lb +``` + +In these diagrams, UB and LB are defined as before. As you can see, +the new ranges `A'` and `B'` are quite different from the range that +would be produced by unifying the variables. + +### What we do now + +Our current technique is to *try* (transactionally) to relate the +existing bounds of A and B, if there are any (i.e., if `UB(A) != top +&& LB(B) != bot`). If that succeeds, we're done. If it fails, then +we merge A and B into same variable. + +This is not clearly the correct course. For example, if `UB(A) != +top` but `LB(B) == bot`, we could conceivably set `LB(B)` to `UB(A)` +and leave the variables unmerged. This is sometimes the better +course, it depends on the program. + +The main case which fails today that I would like to support is: + +```text +fn foo(x: T, y: T) { ... } + +fn bar() { + let x: @mut int = @mut 3; + let y: @int = @3; + foo(x, y); +} +``` + +In principle, the inferencer ought to find that the parameter `T` to +`foo(x, y)` is `@const int`. Today, however, it does not; this is +because the type variable `T` is merged with the type variable for +`X`, and thus inherits its UB/LB of `@mut int`. This leaves no +flexibility for `T` to later adjust to accommodate `@int`. + +### What to do when not all bounds are present + +In the prior discussion we assumed that A.ub was not top and B.lb was +not bot. Unfortunately this is rarely the case. Often type variables +have "lopsided" bounds. For example, if a variable in the program has +been initialized but has not been used, then its corresponding type +variable will have a lower bound but no upper bound. When that +variable is then used, we would like to know its upper bound---but we +don't have one! In this case we'll do different things depending on +how the variable is being used. + +## Transactional support + +Whenever we adjust merge variables or adjust their bounds, we always +keep a record of the old value. This allows the changes to be undone. + +## Regions + +I've only talked about type variables here, but region variables +follow the same principle. They have upper- and lower-bounds. A +region A is a subregion of a region B if A being valid implies that B +is valid. This basically corresponds to the block nesting structure: +the regions for outer block scopes are superregions of those for inner +block scopes. + +## Integral and floating-point type variables + +There is a third variety of type variable that we use only for +inferring the types of unsuffixed integer literals. Integral type +variables differ from general-purpose type variables in that there's +no subtyping relationship among the various integral types, so instead +of associating each variable with an upper and lower bound, we just +use simple unification. Each integer variable is associated with at +most one integer type. Floating point types are handled similarly to +integral types. + +## GLB/LUB + +Computing the greatest-lower-bound and least-upper-bound of two +types/regions is generally straightforward except when type variables +are involved. In that case, we follow a similar "try to use the bounds +when possible but otherwise merge the variables" strategy. In other +words, `GLB(A, B)` where `A` and `B` are variables will often result +in `A` and `B` being merged and the result being `A`. + +## Type coercion + +We have a notion of assignability which differs somewhat from +subtyping; in particular it may cause region borrowing to occur. See +the big comment later in this file on Type Coercion for specifics. + +### In conclusion + +I showed you three ways to relate `A` and `B`. There are also more, +of course, though I'm not sure if there are any more sensible options. +The main point is that there are various options, each of which +produce a distinct range of types for `A` and `B`. Depending on what +the correct values for A and B are, one of these options will be the +right choice: but of course we don't know the right values for A and B +yet, that's what we're trying to find! In our code, we opt to unify +(Option #1). + +# Implementation details + +We make use of a trait-like implementation strategy to consolidate +duplicated code between subtypes, GLB, and LUB computations. See the +section on "Type Combining" below for details. diff --git a/src/librustc/infer/bivariate.rs b/src/librustc/infer/bivariate.rs new file mode 100644 index 00000000000..a9ea395e6b3 --- /dev/null +++ b/src/librustc/infer/bivariate.rs @@ -0,0 +1,117 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Applies the "bivariance relationship" to two types and/or regions. +//! If (A,B) are bivariant then either A <: B or B <: A. It occurs +//! when type/lifetime parameters are unconstrained. Usually this is +//! an error, but we permit it in the specific case where a type +//! parameter is constrained in a where-clause via an associated type. +//! +//! There are several ways one could implement bivariance. You could +//! just do nothing at all, for example, or you could fully verify +//! that one of the two subtyping relationships hold. We choose to +//! thread a middle line: we relate types up to regions, but ignore +//! all region relationships. +//! +//! At one point, handling bivariance in this fashion was necessary +//! for inference, but I'm actually not sure if that is true anymore. +//! In particular, it might be enough to say (A,B) are bivariant for +//! all (A,B). + +use super::combine::{self, CombineFields}; +use super::type_variable::{BiTo}; + +use ty::{self, Ty, TyCtxt}; +use ty::TyVar; +use ty::relate::{Relate, RelateResult, TypeRelation}; + +pub struct Bivariate<'a, 'tcx: 'a> { + fields: CombineFields<'a, 'tcx> +} + +impl<'a, 'tcx> Bivariate<'a, 'tcx> { + pub fn new(fields: CombineFields<'a, 'tcx>) -> Bivariate<'a, 'tcx> { + Bivariate { fields: fields } + } +} + +impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Bivariate<'a, 'tcx> { + fn tag(&self) -> &'static str { "Bivariate" } + + fn tcx(&self) -> &'a TyCtxt<'tcx> { self.fields.tcx() } + + fn a_is_expected(&self) -> bool { self.fields.a_is_expected } + + fn relate_with_variance>(&mut self, + variance: ty::Variance, + a: &T, + b: &T) + -> RelateResult<'tcx, T> + { + match variance { + // If we have Foo and Foo is invariant w/r/t A, + // and we want to assert that + // + // Foo <: Foo || + // Foo <: Foo + // + // then still A must equal B. + ty::Invariant => self.relate(a, b), + + ty::Covariant => self.relate(a, b), + ty::Bivariant => self.relate(a, b), + ty::Contravariant => self.relate(a, b), + } + } + + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + debug!("{}.tys({:?}, {:?})", self.tag(), + a, b); + if a == b { return Ok(a); } + + let infcx = self.fields.infcx; + let a = infcx.type_variables.borrow_mut().replace_if_possible(a); + let b = infcx.type_variables.borrow_mut().replace_if_possible(b); + match (&a.sty, &b.sty) { + (&ty::TyInfer(TyVar(a_id)), &ty::TyInfer(TyVar(b_id))) => { + infcx.type_variables.borrow_mut().relate_vars(a_id, BiTo, b_id); + Ok(a) + } + + (&ty::TyInfer(TyVar(a_id)), _) => { + self.fields.instantiate(b, BiTo, a_id)?; + Ok(a) + } + + (_, &ty::TyInfer(TyVar(b_id))) => { + self.fields.instantiate(a, BiTo, b_id)?; + Ok(a) + } + + _ => { + combine::super_combine_tys(self.fields.infcx, self, a, b) + } + } + } + + fn regions(&mut self, a: ty::Region, _: ty::Region) -> RelateResult<'tcx, ty::Region> { + Ok(a) + } + + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where T: Relate<'a,'tcx> + { + let a1 = self.tcx().erase_late_bound_regions(a); + let b1 = self.tcx().erase_late_bound_regions(b); + let c = self.relate(&a1, &b1)?; + Ok(ty::Binder(c)) + } +} diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs new file mode 100644 index 00000000000..2b30698882d --- /dev/null +++ b/src/librustc/infer/combine.rs @@ -0,0 +1,403 @@ +// Copyright 2012 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/////////////////////////////////////////////////////////////////////////// +// # Type combining +// +// There are four type combiners: equate, sub, lub, and glb. Each +// implements the trait `Combine` and contains methods for combining +// two instances of various things and yielding a new instance. These +// combiner methods always yield a `Result`. There is a lot of +// common code for these operations, implemented as default methods on +// the `Combine` trait. +// +// Each operation may have side-effects on the inference context, +// though these can be unrolled using snapshots. On success, the +// LUB/GLB operations return the appropriate bound. The Eq and Sub +// operations generally return the first operand. +// +// ## Contravariance +// +// When you are relating two things which have a contravariant +// relationship, you should use `contratys()` or `contraregions()`, +// rather than inversing the order of arguments! This is necessary +// because the order of arguments is not relevant for LUB and GLB. It +// is also useful to track which value is the "expected" value in +// terms of error reporting. + +use super::bivariate::Bivariate; +use super::equate::Equate; +use super::glb::Glb; +use super::lub::Lub; +use super::sub::Sub; +use super::{InferCtxt}; +use super::{MiscVariable, TypeTrace}; +use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf}; + +use ty::{IntType, UintType}; +use ty::{self, Ty, TyCtxt}; +use ty::error::TypeError; +use ty::fold::{TypeFolder, TypeFoldable}; +use ty::relate::{Relate, RelateResult, TypeRelation}; + +use syntax::ast; +use syntax::codemap::Span; + +#[derive(Clone)] +pub struct CombineFields<'a, 'tcx: 'a> { + pub infcx: &'a InferCtxt<'a, 'tcx>, + pub a_is_expected: bool, + pub trace: TypeTrace<'tcx>, + pub cause: Option, +} + +pub fn super_combine_tys<'a,'tcx:'a,R>(infcx: &InferCtxt<'a, 'tcx>, + relation: &mut R, + a: Ty<'tcx>, + b: Ty<'tcx>) + -> RelateResult<'tcx, Ty<'tcx>> + where R: TypeRelation<'a,'tcx> +{ + let a_is_expected = relation.a_is_expected(); + + match (&a.sty, &b.sty) { + // Relate integral variables to other types + (&ty::TyInfer(ty::IntVar(a_id)), &ty::TyInfer(ty::IntVar(b_id))) => { + infcx.int_unification_table + .borrow_mut() + .unify_var_var(a_id, b_id) + .map_err(|e| int_unification_error(a_is_expected, e))?; + Ok(a) + } + (&ty::TyInfer(ty::IntVar(v_id)), &ty::TyInt(v)) => { + unify_integral_variable(infcx, a_is_expected, v_id, IntType(v)) + } + (&ty::TyInt(v), &ty::TyInfer(ty::IntVar(v_id))) => { + unify_integral_variable(infcx, !a_is_expected, v_id, IntType(v)) + } + (&ty::TyInfer(ty::IntVar(v_id)), &ty::TyUint(v)) => { + unify_integral_variable(infcx, a_is_expected, v_id, UintType(v)) + } + (&ty::TyUint(v), &ty::TyInfer(ty::IntVar(v_id))) => { + unify_integral_variable(infcx, !a_is_expected, v_id, UintType(v)) + } + + // Relate floating-point variables to other types + (&ty::TyInfer(ty::FloatVar(a_id)), &ty::TyInfer(ty::FloatVar(b_id))) => { + infcx.float_unification_table + .borrow_mut() + .unify_var_var(a_id, b_id) + .map_err(|e| float_unification_error(relation.a_is_expected(), e))?; + Ok(a) + } + (&ty::TyInfer(ty::FloatVar(v_id)), &ty::TyFloat(v)) => { + unify_float_variable(infcx, a_is_expected, v_id, v) + } + (&ty::TyFloat(v), &ty::TyInfer(ty::FloatVar(v_id))) => { + unify_float_variable(infcx, !a_is_expected, v_id, v) + } + + // All other cases of inference are errors + (&ty::TyInfer(_), _) | + (_, &ty::TyInfer(_)) => { + Err(TypeError::Sorts(ty::relate::expected_found(relation, &a, &b))) + } + + + _ => { + ty::relate::super_relate_tys(relation, a, b) + } + } +} + +fn unify_integral_variable<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, + vid_is_expected: bool, + vid: ty::IntVid, + val: ty::IntVarValue) + -> RelateResult<'tcx, Ty<'tcx>> +{ + infcx.int_unification_table + .borrow_mut() + .unify_var_value(vid, val) + .map_err(|e| int_unification_error(vid_is_expected, e))?; + match val { + IntType(v) => Ok(infcx.tcx.mk_mach_int(v)), + UintType(v) => Ok(infcx.tcx.mk_mach_uint(v)), + } +} + +fn unify_float_variable<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, + vid_is_expected: bool, + vid: ty::FloatVid, + val: ast::FloatTy) + -> RelateResult<'tcx, Ty<'tcx>> +{ + infcx.float_unification_table + .borrow_mut() + .unify_var_value(vid, val) + .map_err(|e| float_unification_error(vid_is_expected, e))?; + Ok(infcx.tcx.mk_mach_float(val)) +} + +impl<'a, 'tcx> CombineFields<'a, 'tcx> { + pub fn tcx(&self) -> &'a TyCtxt<'tcx> { + self.infcx.tcx + } + + pub fn switch_expected(&self) -> CombineFields<'a, 'tcx> { + CombineFields { + a_is_expected: !self.a_is_expected, + ..(*self).clone() + } + } + + pub fn equate(&self) -> Equate<'a, 'tcx> { + Equate::new(self.clone()) + } + + pub fn bivariate(&self) -> Bivariate<'a, 'tcx> { + Bivariate::new(self.clone()) + } + + pub fn sub(&self) -> Sub<'a, 'tcx> { + Sub::new(self.clone()) + } + + pub fn lub(&self) -> Lub<'a, 'tcx> { + Lub::new(self.clone()) + } + + pub fn glb(&self) -> Glb<'a, 'tcx> { + Glb::new(self.clone()) + } + + pub fn instantiate(&self, + a_ty: Ty<'tcx>, + dir: RelationDir, + b_vid: ty::TyVid) + -> RelateResult<'tcx, ()> + { + let mut stack = Vec::new(); + stack.push((a_ty, dir, b_vid)); + loop { + // For each turn of the loop, we extract a tuple + // + // (a_ty, dir, b_vid) + // + // to relate. Here dir is either SubtypeOf or + // SupertypeOf. The idea is that we should ensure that + // the type `a_ty` is a subtype or supertype (respectively) of the + // type to which `b_vid` is bound. + // + // If `b_vid` has not yet been instantiated with a type + // (which is always true on the first iteration, but not + // necessarily true on later iterations), we will first + // instantiate `b_vid` with a *generalized* version of + // `a_ty`. Generalization introduces other inference + // variables wherever subtyping could occur (at time of + // this writing, this means replacing free regions with + // region variables). + let (a_ty, dir, b_vid) = match stack.pop() { + None => break, + Some(e) => e, + }; + // Get the actual variable that b_vid has been inferred to + let (b_vid, b_ty) = { + let mut variables = self.infcx.type_variables.borrow_mut(); + let b_vid = variables.root_var(b_vid); + (b_vid, variables.probe_root(b_vid)) + }; + + debug!("instantiate(a_ty={:?} dir={:?} b_vid={:?})", + a_ty, + dir, + b_vid); + + // Check whether `vid` has been instantiated yet. If not, + // make a generalized form of `ty` and instantiate with + // that. + let b_ty = match b_ty { + Some(t) => t, // ...already instantiated. + None => { // ...not yet instantiated: + // Generalize type if necessary. + let generalized_ty = match dir { + EqTo => self.generalize(a_ty, b_vid, false), + BiTo | SupertypeOf | SubtypeOf => self.generalize(a_ty, b_vid, true), + }?; + debug!("instantiate(a_ty={:?}, dir={:?}, \ + b_vid={:?}, generalized_ty={:?})", + a_ty, dir, b_vid, + generalized_ty); + self.infcx.type_variables + .borrow_mut() + .instantiate_and_push( + b_vid, generalized_ty, &mut stack); + generalized_ty + } + }; + + // The original triple was `(a_ty, dir, b_vid)` -- now we have + // resolved `b_vid` to `b_ty`, so apply `(a_ty, dir, b_ty)`: + // + // FIXME(#16847): This code is non-ideal because all these subtype + // relations wind up attributed to the same spans. We need + // to associate causes/spans with each of the relations in + // the stack to get this right. + match dir { + BiTo => self.bivariate().relate(&a_ty, &b_ty), + EqTo => self.equate().relate(&a_ty, &b_ty), + SubtypeOf => self.sub().relate(&a_ty, &b_ty), + SupertypeOf => self.sub().relate_with_variance(ty::Contravariant, &a_ty, &b_ty), + }?; + } + + Ok(()) + } + + /// Attempts to generalize `ty` for the type variable `for_vid`. This checks for cycle -- that + /// is, whether the type `ty` references `for_vid`. If `make_region_vars` is true, it will also + /// replace all regions with fresh variables. Returns `TyError` in the case of a cycle, `Ok` + /// otherwise. + fn generalize(&self, + ty: Ty<'tcx>, + for_vid: ty::TyVid, + make_region_vars: bool) + -> RelateResult<'tcx, Ty<'tcx>> + { + let mut generalize = Generalizer { + infcx: self.infcx, + span: self.trace.origin.span(), + for_vid: for_vid, + make_region_vars: make_region_vars, + cycle_detected: false + }; + let u = ty.fold_with(&mut generalize); + if generalize.cycle_detected { + Err(TypeError::CyclicTy) + } else { + Ok(u) + } + } +} + +struct Generalizer<'cx, 'tcx:'cx> { + infcx: &'cx InferCtxt<'cx, 'tcx>, + span: Span, + for_vid: ty::TyVid, + make_region_vars: bool, + cycle_detected: bool, +} + +impl<'cx, 'tcx> ty::fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> { + fn tcx(&self) -> &TyCtxt<'tcx> { + self.infcx.tcx + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + // Check to see whether the type we are genealizing references + // `vid`. At the same time, also update any type variables to + // the values that they are bound to. This is needed to truly + // check for cycles, but also just makes things readable. + // + // (In particular, you could have something like `$0 = Box<$1>` + // where `$1` has already been instantiated with `Box<$0>`) + match t.sty { + ty::TyInfer(ty::TyVar(vid)) => { + let mut variables = self.infcx.type_variables.borrow_mut(); + let vid = variables.root_var(vid); + if vid == self.for_vid { + self.cycle_detected = true; + self.tcx().types.err + } else { + match variables.probe_root(vid) { + Some(u) => { + drop(variables); + self.fold_ty(u) + } + None => t, + } + } + } + _ => { + t.super_fold_with(self) + } + } + } + + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + match r { + // Never make variables for regions bound within the type itself. + ty::ReLateBound(..) => { return r; } + + // Early-bound regions should really have been substituted away before + // we get to this point. + ty::ReEarlyBound(..) => { + self.tcx().sess.span_bug( + self.span, + &format!("Encountered early bound region when generalizing: {:?}", + r)); + } + + // Always make a fresh region variable for skolemized regions; + // the higher-ranked decision procedures rely on this. + ty::ReSkolemized(..) => { } + + // For anything else, we make a region variable, unless we + // are *equating*, in which case it's just wasteful. + ty::ReEmpty | + ty::ReStatic | + ty::ReScope(..) | + ty::ReVar(..) | + ty::ReFree(..) => { + if !self.make_region_vars { + return r; + } + } + } + + // FIXME: This is non-ideal because we don't give a + // very descriptive origin for this region variable. + self.infcx.next_region_var(MiscVariable(self.span)) + } +} + +pub trait RelateResultCompare<'tcx, T> { + fn compare(&self, t: T, f: F) -> RelateResult<'tcx, T> where + F: FnOnce() -> TypeError<'tcx>; +} + +impl<'tcx, T:Clone + PartialEq> RelateResultCompare<'tcx, T> for RelateResult<'tcx, T> { + fn compare(&self, t: T, f: F) -> RelateResult<'tcx, T> where + F: FnOnce() -> TypeError<'tcx>, + { + self.clone().and_then(|s| { + if s == t { + self.clone() + } else { + Err(f()) + } + }) + } +} + +fn int_unification_error<'tcx>(a_is_expected: bool, v: (ty::IntVarValue, ty::IntVarValue)) + -> TypeError<'tcx> +{ + let (a, b) = v; + TypeError::IntMismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b)) +} + +fn float_unification_error<'tcx>(a_is_expected: bool, + v: (ast::FloatTy, ast::FloatTy)) + -> TypeError<'tcx> +{ + let (a, b) = v; + TypeError::FloatMismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b)) +} diff --git a/src/librustc/infer/equate.rs b/src/librustc/infer/equate.rs new file mode 100644 index 00000000000..3c9c9c57884 --- /dev/null +++ b/src/librustc/infer/equate.rs @@ -0,0 +1,95 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::combine::{self, CombineFields}; +use super::higher_ranked::HigherRankedRelations; +use super::{Subtype}; +use super::type_variable::{EqTo}; + +use ty::{self, Ty, TyCtxt}; +use ty::TyVar; +use ty::relate::{Relate, RelateResult, TypeRelation}; + +/// Ensures `a` is made equal to `b`. Returns `a` on success. +pub struct Equate<'a, 'tcx: 'a> { + fields: CombineFields<'a, 'tcx> +} + +impl<'a, 'tcx> Equate<'a, 'tcx> { + pub fn new(fields: CombineFields<'a, 'tcx>) -> Equate<'a, 'tcx> { + Equate { fields: fields } + } +} + +impl<'a, 'tcx> TypeRelation<'a,'tcx> for Equate<'a, 'tcx> { + fn tag(&self) -> &'static str { "Equate" } + + fn tcx(&self) -> &'a TyCtxt<'tcx> { self.fields.tcx() } + + fn a_is_expected(&self) -> bool { self.fields.a_is_expected } + + fn relate_with_variance>(&mut self, + _: ty::Variance, + a: &T, + b: &T) + -> RelateResult<'tcx, T> + { + self.relate(a, b) + } + + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + debug!("{}.tys({:?}, {:?})", self.tag(), + a, b); + if a == b { return Ok(a); } + + let infcx = self.fields.infcx; + let a = infcx.type_variables.borrow_mut().replace_if_possible(a); + let b = infcx.type_variables.borrow_mut().replace_if_possible(b); + match (&a.sty, &b.sty) { + (&ty::TyInfer(TyVar(a_id)), &ty::TyInfer(TyVar(b_id))) => { + infcx.type_variables.borrow_mut().relate_vars(a_id, EqTo, b_id); + Ok(a) + } + + (&ty::TyInfer(TyVar(a_id)), _) => { + self.fields.instantiate(b, EqTo, a_id)?; + Ok(a) + } + + (_, &ty::TyInfer(TyVar(b_id))) => { + self.fields.instantiate(a, EqTo, b_id)?; + Ok(a) + } + + _ => { + combine::super_combine_tys(self.fields.infcx, self, a, b)?; + Ok(a) + } + } + } + + fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> { + debug!("{}.regions({:?}, {:?})", + self.tag(), + a, + b); + let origin = Subtype(self.fields.trace.clone()); + self.fields.infcx.region_vars.make_eqregion(origin, a, b); + Ok(a) + } + + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where T: Relate<'a, 'tcx> + { + self.fields.higher_ranked_sub(a, b)?; + self.fields.higher_ranked_sub(b, a) + } +} diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs new file mode 100644 index 00000000000..20c01344144 --- /dev/null +++ b/src/librustc/infer/error_reporting.rs @@ -0,0 +1,2050 @@ +// Copyright 2012-2013 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Error Reporting Code for the inference engine +//! +//! Because of the way inference, and in particular region inference, +//! works, it often happens that errors are not detected until far after +//! the relevant line of code has been type-checked. Therefore, there is +//! an elaborate system to track why a particular constraint in the +//! inference graph arose so that we can explain to the user what gave +//! rise to a particular error. +//! +//! The basis of the system are the "origin" types. An "origin" is the +//! reason that a constraint or inference variable arose. There are +//! different "origin" enums for different kinds of constraints/variables +//! (e.g., `TypeOrigin`, `RegionVariableOrigin`). An origin always has +//! a span, but also more information so that we can generate a meaningful +//! error message. +//! +//! Having a catalogue of all the different reasons an error can arise is +//! also useful for other reasons, like cross-referencing FAQs etc, though +//! we are not really taking advantage of this yet. +//! +//! # Region Inference +//! +//! Region inference is particularly tricky because it always succeeds "in +//! the moment" and simply registers a constraint. Then, at the end, we +//! can compute the full graph and report errors, so we need to be able to +//! store and later report what gave rise to the conflicting constraints. +//! +//! # Subtype Trace +//! +//! Determining whether `T1 <: T2` often involves a number of subtypes and +//! subconstraints along the way. A "TypeTrace" is an extended version +//! of an origin that traces the types and other values that were being +//! compared. It is not necessarily comprehensive (in fact, at the time of +//! this writing it only tracks the root values being compared) but I'd +//! like to extend it to include significant "waypoints". For example, if +//! you are comparing `(T1, T2) <: (T3, T4)`, and the problem is that `T2 +//! <: T4` fails, I'd like the trace to include enough information to say +//! "in the 2nd element of the tuple". Similarly, failures when comparing +//! arguments or return types in fn types should be able to cite the +//! specific position, etc. +//! +//! # Reality vs plan +//! +//! Of course, there is still a LOT of code in typeck that has yet to be +//! ported to this system, and which relies on string concatenation at the +//! time of error detection. + +use self::FreshOrKept::*; + +use super::InferCtxt; +use super::TypeTrace; +use super::SubregionOrigin; +use super::RegionVariableOrigin; +use super::ValuePairs; +use super::region_inference::RegionResolutionError; +use super::region_inference::ConcreteFailure; +use super::region_inference::SubSupConflict; +use super::region_inference::GenericBoundFailure; +use super::region_inference::GenericKind; +use super::region_inference::ProcessedErrors; +use super::region_inference::ProcessedErrorOrigin; +use super::region_inference::SameRegions; + +use std::collections::HashSet; + +use front::map as ast_map; +use rustc_front::hir; +use rustc_front::print::pprust; + +use middle::cstore::CrateStore; +use middle::def::Def; +use middle::def_id::DefId; +use infer::{self, TypeOrigin}; +use middle::region; +use ty::subst; +use ty::{self, Ty, TyCtxt, TypeFoldable}; +use ty::{Region, ReFree}; +use ty::error::TypeError; + +use std::cell::{Cell, RefCell}; +use std::char::from_u32; +use std::fmt; +use syntax::ast; +use syntax::errors::DiagnosticBuilder; +use syntax::codemap::{self, Pos, Span}; +use syntax::parse::token; +use syntax::ptr::P; + +impl<'tcx> TyCtxt<'tcx> { + pub fn note_and_explain_region(&self, + err: &mut DiagnosticBuilder, + prefix: &str, + region: ty::Region, + suffix: &str) { + fn item_scope_tag(item: &hir::Item) -> &'static str { + match item.node { + hir::ItemImpl(..) => "impl", + hir::ItemStruct(..) => "struct", + hir::ItemEnum(..) => "enum", + hir::ItemTrait(..) => "trait", + hir::ItemFn(..) => "function body", + _ => "item" + } + } + + fn explain_span(tcx: &TyCtxt, heading: &str, span: Span) + -> (String, Option) { + let lo = tcx.sess.codemap().lookup_char_pos_adj(span.lo); + (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize()), + Some(span)) + } + + let (description, span) = match region { + ty::ReScope(scope) => { + let new_string; + let unknown_scope = || { + format!("{}unknown scope: {:?}{}. Please report a bug.", + prefix, scope, suffix) + }; + let span = match scope.span(&self.region_maps, &self.map) { + Some(s) => s, + None => { + err.note(&unknown_scope()); + return; + } + }; + let tag = match self.map.find(scope.node_id(&self.region_maps)) { + Some(ast_map::NodeBlock(_)) => "block", + Some(ast_map::NodeExpr(expr)) => match expr.node { + hir::ExprCall(..) => "call", + hir::ExprMethodCall(..) => "method call", + hir::ExprMatch(_, _, hir::MatchSource::IfLetDesugar { .. }) => "if let", + hir::ExprMatch(_, _, hir::MatchSource::WhileLetDesugar) => "while let", + hir::ExprMatch(_, _, hir::MatchSource::ForLoopDesugar) => "for", + hir::ExprMatch(..) => "match", + _ => "expression", + }, + Some(ast_map::NodeStmt(_)) => "statement", + Some(ast_map::NodeItem(it)) => item_scope_tag(&it), + Some(_) | None => { + err.span_note(span, &unknown_scope()); + return; + } + }; + let scope_decorated_tag = match self.region_maps.code_extent_data(scope) { + region::CodeExtentData::Misc(_) => tag, + region::CodeExtentData::CallSiteScope { .. } => { + "scope of call-site for function" + } + region::CodeExtentData::ParameterScope { .. } => { + "scope of parameters for function" + } + region::CodeExtentData::DestructionScope(_) => { + new_string = format!("destruction scope surrounding {}", tag); + &new_string[..] + } + region::CodeExtentData::Remainder(r) => { + new_string = format!("block suffix following statement {}", + r.first_statement_index); + &new_string[..] + } + }; + explain_span(self, scope_decorated_tag, span) + } + + ty::ReFree(ref fr) => { + let prefix = match fr.bound_region { + ty::BrAnon(idx) => { + format!("the anonymous lifetime #{} defined on", idx + 1) + } + ty::BrFresh(_) => "an anonymous lifetime defined on".to_owned(), + _ => { + format!("the lifetime {} as defined on", + fr.bound_region) + } + }; + + match self.map.find(fr.scope.node_id(&self.region_maps)) { + Some(ast_map::NodeBlock(ref blk)) => { + let (msg, opt_span) = explain_span(self, "block", blk.span); + (format!("{} {}", prefix, msg), opt_span) + } + Some(ast_map::NodeItem(it)) => { + let tag = item_scope_tag(&it); + let (msg, opt_span) = explain_span(self, tag, it.span); + (format!("{} {}", prefix, msg), opt_span) + } + Some(_) | None => { + // this really should not happen, but it does: + // FIXME(#27942) + (format!("{} unknown free region bounded by scope {:?}", + prefix, fr.scope), None) + } + } + } + + ty::ReStatic => ("the static lifetime".to_owned(), None), + + ty::ReEmpty => ("the empty lifetime".to_owned(), None), + + ty::ReEarlyBound(ref data) => (data.name.to_string(), None), + + // FIXME(#13998) ReSkolemized should probably print like + // ReFree rather than dumping Debug output on the user. + // + // We shouldn't really be having unification failures with ReVar + // and ReLateBound though. + ty::ReSkolemized(..) | ty::ReVar(_) | ty::ReLateBound(..) => { + (format!("lifetime {:?}", region), None) + } + }; + let message = format!("{}{}{}", prefix, description, suffix); + if let Some(span) = span { + err.span_note(span, &message); + } else { + err.note(&message); + } + } +} + +pub trait ErrorReporting<'tcx> { + fn report_region_errors(&self, + errors: &Vec>); + + fn process_errors(&self, errors: &Vec>) + -> Option>>; + + fn report_type_error(&self, + trace: TypeTrace<'tcx>, + terr: &TypeError<'tcx>) + -> DiagnosticBuilder<'tcx>; + + fn check_and_note_conflicting_crates(&self, + err: &mut DiagnosticBuilder, + terr: &TypeError<'tcx>, + sp: Span); + + fn report_and_explain_type_error(&self, + trace: TypeTrace<'tcx>, + terr: &TypeError<'tcx>) + -> DiagnosticBuilder<'tcx>; + + fn values_str(&self, values: &ValuePairs<'tcx>) -> Option; + + fn expected_found_str + TypeFoldable<'tcx>>( + &self, + exp_found: &ty::error::ExpectedFound) + -> Option; + + fn report_concrete_failure(&self, + origin: SubregionOrigin<'tcx>, + sub: Region, + sup: Region) + -> DiagnosticBuilder<'tcx>; + + fn report_generic_bound_failure(&self, + origin: SubregionOrigin<'tcx>, + kind: GenericKind<'tcx>, + sub: Region); + + fn report_sub_sup_conflict(&self, + var_origin: RegionVariableOrigin, + sub_origin: SubregionOrigin<'tcx>, + sub_region: Region, + sup_origin: SubregionOrigin<'tcx>, + sup_region: Region); + + fn report_processed_errors(&self, + origins: &[ProcessedErrorOrigin<'tcx>], + same_regions: &[SameRegions]); + + fn give_suggestion(&self, err: &mut DiagnosticBuilder, same_regions: &[SameRegions]); +} + +trait ErrorReportingHelpers<'tcx> { + fn report_inference_failure(&self, + var_origin: RegionVariableOrigin) + -> DiagnosticBuilder<'tcx>; + + fn note_region_origin(&self, + err: &mut DiagnosticBuilder, + origin: &SubregionOrigin<'tcx>); + + fn give_expl_lifetime_param(&self, + err: &mut DiagnosticBuilder, + decl: &hir::FnDecl, + unsafety: hir::Unsafety, + constness: hir::Constness, + name: ast::Name, + opt_explicit_self: Option<&hir::ExplicitSelf_>, + generics: &hir::Generics, + span: Span); +} + +impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { + fn report_region_errors(&self, + errors: &Vec>) { + debug!("report_region_errors(): {} errors to start", errors.len()); + + // try to pre-process the errors, which will group some of them + // together into a `ProcessedErrors` group: + let processed_errors = self.process_errors(errors); + let errors = processed_errors.as_ref().unwrap_or(errors); + + debug!("report_region_errors: {} errors after preprocessing", errors.len()); + + for error in errors { + match error.clone() { + ConcreteFailure(origin, sub, sup) => { + self.report_concrete_failure(origin, sub, sup).emit(); + } + + GenericBoundFailure(kind, param_ty, sub) => { + self.report_generic_bound_failure(kind, param_ty, sub); + } + + SubSupConflict(var_origin, + sub_origin, sub_r, + sup_origin, sup_r) => { + self.report_sub_sup_conflict(var_origin, + sub_origin, sub_r, + sup_origin, sup_r); + } + + ProcessedErrors(ref origins, + ref same_regions) => { + if !same_regions.is_empty() { + self.report_processed_errors(origins, same_regions); + } + } + } + } + } + + // This method goes through all the errors and try to group certain types + // of error together, for the purpose of suggesting explicit lifetime + // parameters to the user. This is done so that we can have a more + // complete view of what lifetimes should be the same. + // If the return value is an empty vector, it means that processing + // failed (so the return value of this method should not be used). + // + // The method also attempts to weed out messages that seem like + // duplicates that will be unhelpful to the end-user. But + // obviously it never weeds out ALL errors. + fn process_errors(&self, errors: &Vec>) + -> Option>> { + debug!("process_errors()"); + let mut origins = Vec::new(); + + // we collect up ConcreteFailures and SubSupConflicts that are + // relating free-regions bound on the fn-header and group them + // together into this vector + let mut same_regions = Vec::new(); + + // here we put errors that we will not be able to process nicely + let mut other_errors = Vec::new(); + + // we collect up GenericBoundFailures in here. + let mut bound_failures = Vec::new(); + + for error in errors { + match *error { + ConcreteFailure(ref origin, sub, sup) => { + debug!("processing ConcreteFailure"); + match free_regions_from_same_fn(self.tcx, sub, sup) { + Some(ref same_frs) => { + origins.push( + ProcessedErrorOrigin::ConcreteFailure( + origin.clone(), + sub, + sup)); + append_to_same_regions(&mut same_regions, same_frs); + } + _ => { + other_errors.push(error.clone()); + } + } + } + SubSupConflict(ref var_origin, _, sub_r, _, sup_r) => { + debug!("processing SubSupConflict sub: {:?} sup: {:?}", sub_r, sup_r); + match free_regions_from_same_fn(self.tcx, sub_r, sup_r) { + Some(ref same_frs) => { + origins.push( + ProcessedErrorOrigin::VariableFailure( + var_origin.clone())); + append_to_same_regions(&mut same_regions, same_frs); + } + None => { + other_errors.push(error.clone()); + } + } + } + GenericBoundFailure(ref origin, ref kind, region) => { + bound_failures.push((origin.clone(), kind.clone(), region)); + } + ProcessedErrors(..) => { + panic!("should not encounter a `ProcessedErrors` yet: {:?}", error) + } + } + } + + // ok, let's pull together the errors, sorted in an order that + // we think will help user the best + let mut processed_errors = vec![]; + + // first, put the processed errors, if any + if !same_regions.is_empty() { + let common_scope_id = same_regions[0].scope_id; + for sr in &same_regions { + // Since ProcessedErrors is used to reconstruct the function + // declaration, we want to make sure that they are, in fact, + // from the same scope + if sr.scope_id != common_scope_id { + debug!("returning empty result from process_errors because + {} != {}", sr.scope_id, common_scope_id); + return None; + } + } + assert!(origins.len() > 0); + let pe = ProcessedErrors(origins, same_regions); + debug!("errors processed: {:?}", pe); + processed_errors.push(pe); + } + + // next, put the other misc errors + processed_errors.extend(other_errors); + + // finally, put the `T: 'a` errors, but only if there were no + // other errors. otherwise, these have a very high rate of + // being unhelpful in practice. This is because they are + // basically secondary checks that test the state of the + // region graph after the rest of inference is done, and the + // other kinds of errors indicate that the region constraint + // graph is internally inconsistent, so these test results are + // likely to be meaningless. + if processed_errors.is_empty() { + for (origin, kind, region) in bound_failures { + processed_errors.push(GenericBoundFailure(origin, kind, region)); + } + } + + // we should always wind up with SOME errors, unless there were no + // errors to start + assert!(if errors.len() > 0 {processed_errors.len() > 0} else {true}); + + return Some(processed_errors); + + #[derive(Debug)] + struct FreeRegionsFromSameFn { + sub_fr: ty::FreeRegion, + sup_fr: ty::FreeRegion, + scope_id: ast::NodeId + } + + impl FreeRegionsFromSameFn { + fn new(sub_fr: ty::FreeRegion, + sup_fr: ty::FreeRegion, + scope_id: ast::NodeId) + -> FreeRegionsFromSameFn { + FreeRegionsFromSameFn { + sub_fr: sub_fr, + sup_fr: sup_fr, + scope_id: scope_id + } + } + } + + fn free_regions_from_same_fn(tcx: &TyCtxt, + sub: Region, + sup: Region) + -> Option { + debug!("free_regions_from_same_fn(sub={:?}, sup={:?})", sub, sup); + let (scope_id, fr1, fr2) = match (sub, sup) { + (ReFree(fr1), ReFree(fr2)) => { + if fr1.scope != fr2.scope { + return None + } + assert!(fr1.scope == fr2.scope); + (fr1.scope.node_id(&tcx.region_maps), fr1, fr2) + }, + _ => return None + }; + let parent = tcx.map.get_parent(scope_id); + let parent_node = tcx.map.find(parent); + match parent_node { + Some(node) => match node { + ast_map::NodeItem(item) => match item.node { + hir::ItemFn(..) => { + Some(FreeRegionsFromSameFn::new(fr1, fr2, scope_id)) + }, + _ => None + }, + ast_map::NodeImplItem(..) | + ast_map::NodeTraitItem(..) => { + Some(FreeRegionsFromSameFn::new(fr1, fr2, scope_id)) + }, + _ => None + }, + None => { + debug!("no parent node of scope_id {}", scope_id); + None + } + } + } + + fn append_to_same_regions(same_regions: &mut Vec, + same_frs: &FreeRegionsFromSameFn) { + debug!("append_to_same_regions(same_regions={:?}, same_frs={:?})", + same_regions, same_frs); + let scope_id = same_frs.scope_id; + let (sub_fr, sup_fr) = (same_frs.sub_fr, same_frs.sup_fr); + for sr in same_regions.iter_mut() { + if sr.contains(&sup_fr.bound_region) && scope_id == sr.scope_id { + sr.push(sub_fr.bound_region); + return + } + } + same_regions.push(SameRegions { + scope_id: scope_id, + regions: vec!(sub_fr.bound_region, sup_fr.bound_region) + }) + } + } + + fn report_type_error(&self, + trace: TypeTrace<'tcx>, + terr: &TypeError<'tcx>) + -> DiagnosticBuilder<'tcx> { + let expected_found_str = match self.values_str(&trace.values) { + Some(v) => v, + None => { + return self.tcx.sess.diagnostic().struct_dummy(); /* derived error */ + } + }; + + let is_simple_error = if let &TypeError::Sorts(ref values) = terr { + values.expected.is_primitive() && values.found.is_primitive() + } else { + false + }; + + let expected_found_str = if is_simple_error { + expected_found_str + } else { + format!("{} ({})", expected_found_str, terr) + }; + + let mut err = struct_span_err!(self.tcx.sess, + trace.origin.span(), + E0308, + "{}: {}", + trace.origin, + expected_found_str); + + self.check_and_note_conflicting_crates(&mut err, terr, trace.origin.span()); + + match trace.origin { + TypeOrigin::MatchExpressionArm(_, arm_span, source) => match source { + hir::MatchSource::IfLetDesugar{..} => { + err.span_note(arm_span, "`if let` arm with an incompatible type"); + } + _ => { + err.span_note(arm_span, "match arm with an incompatible type"); + } + }, + _ => () + } + err + } + + /// Adds a note if the types come from similarly named crates + fn check_and_note_conflicting_crates(&self, + err: &mut DiagnosticBuilder, + terr: &TypeError<'tcx>, + sp: Span) { + let report_path_match = |err: &mut DiagnosticBuilder, did1: DefId, did2: DefId| { + // Only external crates, if either is from a local + // module we could have false positives + if !(did1.is_local() || did2.is_local()) && did1.krate != did2.krate { + let exp_path = self.tcx.with_path(did1, + |p| p.map(|x| x.to_string()) + .collect::>()); + let found_path = self.tcx.with_path(did2, + |p| p.map(|x| x.to_string()) + .collect::>()); + // We compare strings because PathMod and PathName can be different + // for imported and non-imported crates + if exp_path == found_path { + let crate_name = self.tcx.sess.cstore.crate_name(did1.krate); + err.span_note(sp, &format!("Perhaps two different versions \ + of crate `{}` are being used?", + crate_name)); + } + } + }; + match *terr { + TypeError::Sorts(ref exp_found) => { + // if they are both "path types", there's a chance of ambiguity + // due to different versions of the same crate + match (&exp_found.expected.sty, &exp_found.found.sty) { + (&ty::TyEnum(ref exp_adt, _), &ty::TyEnum(ref found_adt, _)) | + (&ty::TyStruct(ref exp_adt, _), &ty::TyStruct(ref found_adt, _)) | + (&ty::TyEnum(ref exp_adt, _), &ty::TyStruct(ref found_adt, _)) | + (&ty::TyStruct(ref exp_adt, _), &ty::TyEnum(ref found_adt, _)) => { + report_path_match(err, exp_adt.did, found_adt.did); + }, + _ => () + } + }, + TypeError::Traits(ref exp_found) => { + report_path_match(err, exp_found.expected, exp_found.found); + }, + _ => () // FIXME(#22750) handle traits and stuff + } + } + + fn report_and_explain_type_error(&self, + trace: TypeTrace<'tcx>, + terr: &TypeError<'tcx>) + -> DiagnosticBuilder<'tcx> { + let span = trace.origin.span(); + let mut err = self.report_type_error(trace, terr); + self.tcx.note_and_explain_type_err(&mut err, terr, span); + err + } + + /// Returns a string of the form "expected `{}`, found `{}`", or None if this is a derived + /// error. + fn values_str(&self, values: &ValuePairs<'tcx>) -> Option { + match *values { + infer::Types(ref exp_found) => self.expected_found_str(exp_found), + infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found), + infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found) + } + } + + fn expected_found_str + TypeFoldable<'tcx>>( + &self, + exp_found: &ty::error::ExpectedFound) + -> Option + { + let expected = exp_found.expected.resolve(self); + if expected.references_error() { + return None; + } + + let found = exp_found.found.resolve(self); + if found.references_error() { + return None; + } + + Some(format!("expected `{}`, found `{}`", + expected, + found)) + } + + fn report_generic_bound_failure(&self, + origin: SubregionOrigin<'tcx>, + bound_kind: GenericKind<'tcx>, + sub: Region) + { + // FIXME: it would be better to report the first error message + // with the span of the parameter itself, rather than the span + // where the error was detected. But that span is not readily + // accessible. + + let labeled_user_string = match bound_kind { + GenericKind::Param(ref p) => + format!("the parameter type `{}`", p), + GenericKind::Projection(ref p) => + format!("the associated type `{}`", p), + }; + + let mut err = match sub { + ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => { + // Does the required lifetime have a nice name we can print? + let mut err = struct_span_err!(self.tcx.sess, + origin.span(), + E0309, + "{} may not live long enough", + labeled_user_string); + err.fileline_help(origin.span(), + &format!("consider adding an explicit lifetime bound `{}: {}`...", + bound_kind, + sub)); + err + } + + ty::ReStatic => { + // Does the required lifetime have a nice name we can print? + let mut err = struct_span_err!(self.tcx.sess, + origin.span(), + E0310, + "{} may not live long enough", + labeled_user_string); + err.fileline_help(origin.span(), + &format!("consider adding an explicit lifetime \ + bound `{}: 'static`...", + bound_kind)); + err + } + + _ => { + // If not, be less specific. + let mut err = struct_span_err!(self.tcx.sess, + origin.span(), + E0311, + "{} may not live long enough", + labeled_user_string); + err.fileline_help(origin.span(), + &format!("consider adding an explicit lifetime bound for `{}`", + bound_kind)); + self.tcx.note_and_explain_region( + &mut err, + &format!("{} must be valid for ", labeled_user_string), + sub, + "..."); + err + } + }; + + self.note_region_origin(&mut err, &origin); + err.emit(); + } + + fn report_concrete_failure(&self, + origin: SubregionOrigin<'tcx>, + sub: Region, + sup: Region) + -> DiagnosticBuilder<'tcx> { + match origin { + infer::Subtype(trace) => { + let terr = TypeError::RegionsDoesNotOutlive(sup, sub); + self.report_and_explain_type_error(trace, &terr) + } + infer::Reborrow(span) => { + let mut err = struct_span_err!(self.tcx.sess, span, E0312, + "lifetime of reference outlines \ + lifetime of borrowed content..."); + self.tcx.note_and_explain_region(&mut err, + "...the reference is valid for ", + sub, + "..."); + self.tcx.note_and_explain_region(&mut err, + "...but the borrowed content is only valid for ", + sup, + ""); + err + } + infer::ReborrowUpvar(span, ref upvar_id) => { + let mut err = struct_span_err!(self.tcx.sess, span, E0313, + "lifetime of borrowed pointer outlives \ + lifetime of captured variable `{}`...", + self.tcx.local_var_name_str(upvar_id.var_id)); + self.tcx.note_and_explain_region(&mut err, + "...the borrowed pointer is valid for ", + sub, + "..."); + self.tcx.note_and_explain_region(&mut err, + &format!("...but `{}` is only valid for ", + self.tcx.local_var_name_str(upvar_id.var_id)), + sup, + ""); + err + } + infer::InfStackClosure(span) => { + let mut err = struct_span_err!(self.tcx.sess, span, E0314, + "closure outlives stack frame"); + self.tcx.note_and_explain_region(&mut err, + "...the closure must be valid for ", + sub, + "..."); + self.tcx.note_and_explain_region(&mut err, + "...but the closure's stack frame is only valid for ", + sup, + ""); + err + } + infer::InvokeClosure(span) => { + let mut err = struct_span_err!(self.tcx.sess, span, E0315, + "cannot invoke closure outside of its lifetime"); + self.tcx.note_and_explain_region(&mut err, + "the closure is only valid for ", + sup, + ""); + err + } + infer::DerefPointer(span) => { + let mut err = struct_span_err!(self.tcx.sess, span, E0473, + "dereference of reference outside its lifetime"); + self.tcx.note_and_explain_region(&mut err, + "the reference is only valid for ", + sup, + ""); + err + } + infer::FreeVariable(span, id) => { + let mut err = struct_span_err!(self.tcx.sess, span, E0474, + "captured variable `{}` does not outlive the enclosing closure", + self.tcx.local_var_name_str(id)); + self.tcx.note_and_explain_region(&mut err, + "captured variable is valid for ", + sup, + ""); + self.tcx.note_and_explain_region(&mut err, + "closure is valid for ", + sub, + ""); + err + } + infer::IndexSlice(span) => { + let mut err = struct_span_err!(self.tcx.sess, span, E0475, + "index of slice outside its lifetime"); + self.tcx.note_and_explain_region(&mut err, + "the slice is only valid for ", + sup, + ""); + err + } + infer::RelateObjectBound(span) => { + let mut err = struct_span_err!(self.tcx.sess, span, E0476, + "lifetime of the source pointer does not outlive \ + lifetime bound of the object type"); + self.tcx.note_and_explain_region(&mut err, + "object type is valid for ", + sub, + ""); + self.tcx.note_and_explain_region(&mut err, + "source pointer is only valid for ", + sup, + ""); + err + } + infer::RelateParamBound(span, ty) => { + let mut err = struct_span_err!(self.tcx.sess, span, E0477, + "the type `{}` does not fulfill the required lifetime", + self.ty_to_string(ty)); + self.tcx.note_and_explain_region(&mut err, + "type must outlive ", + sub, + ""); + err + } + infer::RelateRegionParamBound(span) => { + let mut err = struct_span_err!(self.tcx.sess, span, E0478, + "lifetime bound not satisfied"); + self.tcx.note_and_explain_region(&mut err, + "lifetime parameter instantiated with ", + sup, + ""); + self.tcx.note_and_explain_region(&mut err, + "but lifetime parameter must outlive ", + sub, + ""); + err + } + infer::RelateDefaultParamBound(span, ty) => { + let mut err = struct_span_err!(self.tcx.sess, span, E0479, + "the type `{}` (provided as the value of \ + a type parameter) is not valid at this point", + self.ty_to_string(ty)); + self.tcx.note_and_explain_region(&mut err, + "type must outlive ", + sub, + ""); + err + } + infer::CallRcvr(span) => { + let mut err = struct_span_err!(self.tcx.sess, span, E0480, + "lifetime of method receiver does not outlive \ + the method call"); + self.tcx.note_and_explain_region(&mut err, + "the receiver is only valid for ", + sup, + ""); + err + } + infer::CallArg(span) => { + let mut err = struct_span_err!(self.tcx.sess, span, E0481, + "lifetime of function argument does not outlive \ + the function call"); + self.tcx.note_and_explain_region(&mut err, + "the function argument is only valid for ", + sup, + ""); + err + } + infer::CallReturn(span) => { + let mut err = struct_span_err!(self.tcx.sess, span, E0482, + "lifetime of return value does not outlive \ + the function call"); + self.tcx.note_and_explain_region(&mut err, + "the return value is only valid for ", + sup, + ""); + err + } + infer::Operand(span) => { + let mut err = struct_span_err!(self.tcx.sess, span, E0483, + "lifetime of operand does not outlive \ + the operation"); + self.tcx.note_and_explain_region(&mut err, + "the operand is only valid for ", + sup, + ""); + err + } + infer::AddrOf(span) => { + let mut err = struct_span_err!(self.tcx.sess, span, E0484, + "reference is not valid at the time of borrow"); + self.tcx.note_and_explain_region(&mut err, + "the borrow is only valid for ", + sup, + ""); + err + } + infer::AutoBorrow(span) => { + let mut err = struct_span_err!(self.tcx.sess, span, E0485, + "automatically reference is not valid \ + at the time of borrow"); + self.tcx.note_and_explain_region(&mut err, + "the automatic borrow is only valid for ", + sup, + ""); + err + } + infer::ExprTypeIsNotInScope(t, span) => { + let mut err = struct_span_err!(self.tcx.sess, span, E0486, + "type of expression contains references \ + that are not valid during the expression: `{}`", + self.ty_to_string(t)); + self.tcx.note_and_explain_region(&mut err, + "type is only valid for ", + sup, + ""); + err + } + infer::SafeDestructor(span) => { + let mut err = struct_span_err!(self.tcx.sess, span, E0487, + "unsafe use of destructor: destructor might be called \ + while references are dead"); + // FIXME (22171): terms "super/subregion" are suboptimal + self.tcx.note_and_explain_region(&mut err, + "superregion: ", + sup, + ""); + self.tcx.note_and_explain_region(&mut err, + "subregion: ", + sub, + ""); + err + } + infer::BindingTypeIsNotValidAtDecl(span) => { + let mut err = struct_span_err!(self.tcx.sess, span, E0488, + "lifetime of variable does not enclose its declaration"); + self.tcx.note_and_explain_region(&mut err, + "the variable is only valid for ", + sup, + ""); + err + } + infer::ParameterInScope(_, span) => { + let mut err = struct_span_err!(self.tcx.sess, span, E0489, + "type/lifetime parameter not in scope here"); + self.tcx.note_and_explain_region(&mut err, + "the parameter is only valid for ", + sub, + ""); + err + } + infer::DataBorrowed(ty, span) => { + let mut err = struct_span_err!(self.tcx.sess, span, E0490, + "a value of type `{}` is borrowed for too long", + self.ty_to_string(ty)); + self.tcx.note_and_explain_region(&mut err, "the type is valid for ", sub, ""); + self.tcx.note_and_explain_region(&mut err, "but the borrow lasts for ", sup, ""); + err + } + infer::ReferenceOutlivesReferent(ty, span) => { + let mut err = struct_span_err!(self.tcx.sess, span, E0491, + "in type `{}`, reference has a longer lifetime \ + than the data it references", + self.ty_to_string(ty)); + self.tcx.note_and_explain_region(&mut err, + "the pointer is valid for ", + sub, + ""); + self.tcx.note_and_explain_region(&mut err, + "but the referenced data is only valid for ", + sup, + ""); + err + } + } + } + + fn report_sub_sup_conflict(&self, + var_origin: RegionVariableOrigin, + sub_origin: SubregionOrigin<'tcx>, + sub_region: Region, + sup_origin: SubregionOrigin<'tcx>, + sup_region: Region) { + let mut err = self.report_inference_failure(var_origin); + + self.tcx.note_and_explain_region(&mut err, + "first, the lifetime cannot outlive ", + sup_region, + "..."); + + self.note_region_origin(&mut err, &sup_origin); + + self.tcx.note_and_explain_region(&mut err, + "but, the lifetime must be valid for ", + sub_region, + "..."); + + self.note_region_origin(&mut err, &sub_origin); + err.emit(); + } + + fn report_processed_errors(&self, + origins: &[ProcessedErrorOrigin<'tcx>], + same_regions: &[SameRegions]) { + for (i, origin) in origins.iter().enumerate() { + let mut err = match *origin { + ProcessedErrorOrigin::VariableFailure(ref var_origin) => + self.report_inference_failure(var_origin.clone()), + ProcessedErrorOrigin::ConcreteFailure(ref sr_origin, sub, sup) => + self.report_concrete_failure(sr_origin.clone(), sub, sup), + }; + + // attach the suggestion to the last such error + if i == origins.len() - 1 { + self.give_suggestion(&mut err, same_regions); + } + + err.emit(); + } + } + + fn give_suggestion(&self, err: &mut DiagnosticBuilder, same_regions: &[SameRegions]) { + let scope_id = same_regions[0].scope_id; + let parent = self.tcx.map.get_parent(scope_id); + let parent_node = self.tcx.map.find(parent); + let taken = lifetimes_in_scope(self.tcx, scope_id); + let life_giver = LifeGiver::with_taken(&taken[..]); + let node_inner = match parent_node { + Some(ref node) => match *node { + ast_map::NodeItem(ref item) => { + match item.node { + hir::ItemFn(ref fn_decl, unsafety, constness, _, ref gen, _) => { + Some((fn_decl, gen, unsafety, constness, + item.name, None, item.span)) + }, + _ => None + } + } + ast_map::NodeImplItem(item) => { + match item.node { + hir::ImplItemKind::Method(ref sig, _) => { + Some((&sig.decl, + &sig.generics, + sig.unsafety, + sig.constness, + item.name, + Some(&sig.explicit_self.node), + item.span)) + } + _ => None, + } + }, + ast_map::NodeTraitItem(item) => { + match item.node { + hir::MethodTraitItem(ref sig, Some(_)) => { + Some((&sig.decl, + &sig.generics, + sig.unsafety, + sig.constness, + item.name, + Some(&sig.explicit_self.node), + item.span)) + } + _ => None + } + } + _ => None + }, + None => None + }; + let (fn_decl, generics, unsafety, constness, name, expl_self, span) + = node_inner.expect("expect item fn"); + let rebuilder = Rebuilder::new(self.tcx, fn_decl, expl_self, + generics, same_regions, &life_giver); + let (fn_decl, expl_self, generics) = rebuilder.rebuild(); + self.give_expl_lifetime_param(err, &fn_decl, unsafety, constness, name, + expl_self.as_ref(), &generics, span); + } +} + +struct RebuildPathInfo<'a> { + path: &'a hir::Path, + // indexes to insert lifetime on path.lifetimes + indexes: Vec, + // number of lifetimes we expect to see on the type referred by `path` + // (e.g., expected=1 for struct Foo<'a>) + expected: u32, + anon_nums: &'a HashSet, + region_names: &'a HashSet +} + +struct Rebuilder<'a, 'tcx: 'a> { + tcx: &'a TyCtxt<'tcx>, + fn_decl: &'a hir::FnDecl, + expl_self_opt: Option<&'a hir::ExplicitSelf_>, + generics: &'a hir::Generics, + same_regions: &'a [SameRegions], + life_giver: &'a LifeGiver, + cur_anon: Cell, + inserted_anons: RefCell>, +} + +enum FreshOrKept { + Fresh, + Kept +} + +impl<'a, 'tcx> Rebuilder<'a, 'tcx> { + fn new(tcx: &'a TyCtxt<'tcx>, + fn_decl: &'a hir::FnDecl, + expl_self_opt: Option<&'a hir::ExplicitSelf_>, + generics: &'a hir::Generics, + same_regions: &'a [SameRegions], + life_giver: &'a LifeGiver) + -> Rebuilder<'a, 'tcx> { + Rebuilder { + tcx: tcx, + fn_decl: fn_decl, + expl_self_opt: expl_self_opt, + generics: generics, + same_regions: same_regions, + life_giver: life_giver, + cur_anon: Cell::new(0), + inserted_anons: RefCell::new(HashSet::new()), + } + } + + fn rebuild(&self) + -> (hir::FnDecl, Option, hir::Generics) { + let mut expl_self_opt = self.expl_self_opt.cloned(); + let mut inputs = self.fn_decl.inputs.clone(); + let mut output = self.fn_decl.output.clone(); + let mut ty_params = self.generics.ty_params.clone(); + let where_clause = self.generics.where_clause.clone(); + let mut kept_lifetimes = HashSet::new(); + for sr in self.same_regions { + self.cur_anon.set(0); + self.offset_cur_anon(); + let (anon_nums, region_names) = + self.extract_anon_nums_and_names(sr); + let (lifetime, fresh_or_kept) = self.pick_lifetime(®ion_names); + match fresh_or_kept { + Kept => { kept_lifetimes.insert(lifetime.name); } + _ => () + } + expl_self_opt = self.rebuild_expl_self(expl_self_opt, lifetime, + &anon_nums, ®ion_names); + inputs = self.rebuild_args_ty(&inputs[..], lifetime, + &anon_nums, ®ion_names); + output = self.rebuild_output(&output, lifetime, &anon_nums, ®ion_names); + ty_params = self.rebuild_ty_params(ty_params, lifetime, + ®ion_names); + } + let fresh_lifetimes = self.life_giver.get_generated_lifetimes(); + let all_region_names = self.extract_all_region_names(); + let generics = self.rebuild_generics(self.generics, + &fresh_lifetimes, + &kept_lifetimes, + &all_region_names, + ty_params, + where_clause); + let new_fn_decl = hir::FnDecl { + inputs: inputs, + output: output, + variadic: self.fn_decl.variadic + }; + (new_fn_decl, expl_self_opt, generics) + } + + fn pick_lifetime(&self, + region_names: &HashSet) + -> (hir::Lifetime, FreshOrKept) { + if !region_names.is_empty() { + // It's not necessary to convert the set of region names to a + // vector of string and then sort them. However, it makes the + // choice of lifetime name deterministic and thus easier to test. + let mut names = Vec::new(); + for rn in region_names { + let lt_name = rn.to_string(); + names.push(lt_name); + } + names.sort(); + let name = token::intern(&names[0]); + return (name_to_dummy_lifetime(name), Kept); + } + return (self.life_giver.give_lifetime(), Fresh); + } + + fn extract_anon_nums_and_names(&self, same_regions: &SameRegions) + -> (HashSet, HashSet) { + let mut anon_nums = HashSet::new(); + let mut region_names = HashSet::new(); + for br in &same_regions.regions { + match *br { + ty::BrAnon(i) => { + anon_nums.insert(i); + } + ty::BrNamed(_, name) => { + region_names.insert(name); + } + _ => () + } + } + (anon_nums, region_names) + } + + fn extract_all_region_names(&self) -> HashSet { + let mut all_region_names = HashSet::new(); + for sr in self.same_regions { + for br in &sr.regions { + match *br { + ty::BrNamed(_, name) => { + all_region_names.insert(name); + } + _ => () + } + } + } + all_region_names + } + + fn inc_cur_anon(&self, n: u32) { + let anon = self.cur_anon.get(); + self.cur_anon.set(anon+n); + } + + fn offset_cur_anon(&self) { + let mut anon = self.cur_anon.get(); + while self.inserted_anons.borrow().contains(&anon) { + anon += 1; + } + self.cur_anon.set(anon); + } + + fn inc_and_offset_cur_anon(&self, n: u32) { + self.inc_cur_anon(n); + self.offset_cur_anon(); + } + + fn track_anon(&self, anon: u32) { + self.inserted_anons.borrow_mut().insert(anon); + } + + fn rebuild_ty_params(&self, + ty_params: hir::HirVec, + lifetime: hir::Lifetime, + region_names: &HashSet) + -> hir::HirVec { + ty_params.iter().map(|ty_param| { + let bounds = self.rebuild_ty_param_bounds(ty_param.bounds.clone(), + lifetime, + region_names); + hir::TyParam { + name: ty_param.name, + id: ty_param.id, + bounds: bounds, + default: ty_param.default.clone(), + span: ty_param.span, + } + }).collect() + } + + fn rebuild_ty_param_bounds(&self, + ty_param_bounds: hir::TyParamBounds, + lifetime: hir::Lifetime, + region_names: &HashSet) + -> hir::TyParamBounds { + ty_param_bounds.iter().map(|tpb| { + match tpb { + &hir::RegionTyParamBound(lt) => { + // FIXME -- it's unclear whether I'm supposed to + // substitute lifetime here. I suspect we need to + // be passing down a map. + hir::RegionTyParamBound(lt) + } + &hir::TraitTyParamBound(ref poly_tr, modifier) => { + let tr = &poly_tr.trait_ref; + let last_seg = tr.path.segments.last().unwrap(); + let mut insert = Vec::new(); + let lifetimes = last_seg.parameters.lifetimes(); + for (i, lt) in lifetimes.iter().enumerate() { + if region_names.contains(<.name) { + insert.push(i as u32); + } + } + let rebuild_info = RebuildPathInfo { + path: &tr.path, + indexes: insert, + expected: lifetimes.len() as u32, + anon_nums: &HashSet::new(), + region_names: region_names + }; + let new_path = self.rebuild_path(rebuild_info, lifetime); + hir::TraitTyParamBound(hir::PolyTraitRef { + bound_lifetimes: poly_tr.bound_lifetimes.clone(), + trait_ref: hir::TraitRef { + path: new_path, + ref_id: tr.ref_id, + }, + span: poly_tr.span, + }, modifier) + } + } + }).collect() + } + + fn rebuild_expl_self(&self, + expl_self_opt: Option, + lifetime: hir::Lifetime, + anon_nums: &HashSet, + region_names: &HashSet) + -> Option { + match expl_self_opt { + Some(ref expl_self) => match *expl_self { + hir::SelfRegion(lt_opt, muta, id) => match lt_opt { + Some(lt) => if region_names.contains(<.name) { + return Some(hir::SelfRegion(Some(lifetime), muta, id)); + }, + None => { + let anon = self.cur_anon.get(); + self.inc_and_offset_cur_anon(1); + if anon_nums.contains(&anon) { + self.track_anon(anon); + return Some(hir::SelfRegion(Some(lifetime), muta, id)); + } + } + }, + _ => () + }, + None => () + } + expl_self_opt + } + + fn rebuild_generics(&self, + generics: &hir::Generics, + add: &Vec, + keep: &HashSet, + remove: &HashSet, + ty_params: hir::HirVec, + where_clause: hir::WhereClause) + -> hir::Generics { + let mut lifetimes = Vec::new(); + for lt in add { + lifetimes.push(hir::LifetimeDef { lifetime: *lt, + bounds: hir::HirVec::new() }); + } + for lt in &generics.lifetimes { + if keep.contains(<.lifetime.name) || + !remove.contains(<.lifetime.name) { + lifetimes.push((*lt).clone()); + } + } + hir::Generics { + lifetimes: lifetimes.into(), + ty_params: ty_params, + where_clause: where_clause, + } + } + + fn rebuild_args_ty(&self, + inputs: &[hir::Arg], + lifetime: hir::Lifetime, + anon_nums: &HashSet, + region_names: &HashSet) + -> hir::HirVec { + let mut new_inputs = Vec::new(); + for arg in inputs { + let new_ty = self.rebuild_arg_ty_or_output(&arg.ty, lifetime, + anon_nums, region_names); + let possibly_new_arg = hir::Arg { + ty: new_ty, + pat: arg.pat.clone(), + id: arg.id + }; + new_inputs.push(possibly_new_arg); + } + new_inputs.into() + } + + fn rebuild_output(&self, ty: &hir::FunctionRetTy, + lifetime: hir::Lifetime, + anon_nums: &HashSet, + region_names: &HashSet) -> hir::FunctionRetTy { + match *ty { + hir::Return(ref ret_ty) => hir::Return( + self.rebuild_arg_ty_or_output(&ret_ty, lifetime, anon_nums, region_names) + ), + hir::DefaultReturn(span) => hir::DefaultReturn(span), + hir::NoReturn(span) => hir::NoReturn(span) + } + } + + fn rebuild_arg_ty_or_output(&self, + ty: &hir::Ty, + lifetime: hir::Lifetime, + anon_nums: &HashSet, + region_names: &HashSet) + -> P { + let mut new_ty = P(ty.clone()); + let mut ty_queue = vec!(ty); + while !ty_queue.is_empty() { + let cur_ty = ty_queue.remove(0); + match cur_ty.node { + hir::TyRptr(lt_opt, ref mut_ty) => { + let rebuild = match lt_opt { + Some(lt) => region_names.contains(<.name), + None => { + let anon = self.cur_anon.get(); + let rebuild = anon_nums.contains(&anon); + if rebuild { + self.track_anon(anon); + } + self.inc_and_offset_cur_anon(1); + rebuild + } + }; + if rebuild { + let to = hir::Ty { + id: cur_ty.id, + node: hir::TyRptr(Some(lifetime), mut_ty.clone()), + span: cur_ty.span + }; + new_ty = self.rebuild_ty(new_ty, P(to)); + } + ty_queue.push(&mut_ty.ty); + } + hir::TyPath(ref maybe_qself, ref path) => { + let a_def = match self.tcx.def_map.borrow().get(&cur_ty.id) { + None => { + self.tcx + .sess + .fatal(&format!( + "unbound path {}", + pprust::path_to_string(path))) + } + Some(d) => d.full_def() + }; + match a_def { + Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) => { + let generics = self.tcx.lookup_item_type(did).generics; + + let expected = + generics.regions.len(subst::TypeSpace) as u32; + let lifetimes = + path.segments.last().unwrap().parameters.lifetimes(); + let mut insert = Vec::new(); + if lifetimes.is_empty() { + let anon = self.cur_anon.get(); + for (i, a) in (anon..anon+expected).enumerate() { + if anon_nums.contains(&a) { + insert.push(i as u32); + } + self.track_anon(a); + } + self.inc_and_offset_cur_anon(expected); + } else { + for (i, lt) in lifetimes.iter().enumerate() { + if region_names.contains(<.name) { + insert.push(i as u32); + } + } + } + let rebuild_info = RebuildPathInfo { + path: path, + indexes: insert, + expected: expected, + anon_nums: anon_nums, + region_names: region_names + }; + let new_path = self.rebuild_path(rebuild_info, lifetime); + let qself = maybe_qself.as_ref().map(|qself| { + hir::QSelf { + ty: self.rebuild_arg_ty_or_output(&qself.ty, lifetime, + anon_nums, region_names), + position: qself.position + } + }); + let to = hir::Ty { + id: cur_ty.id, + node: hir::TyPath(qself, new_path), + span: cur_ty.span + }; + new_ty = self.rebuild_ty(new_ty, P(to)); + } + _ => () + } + } + + hir::TyPtr(ref mut_ty) => { + ty_queue.push(&mut_ty.ty); + } + hir::TyVec(ref ty) | + hir::TyFixedLengthVec(ref ty, _) => { + ty_queue.push(&ty); + } + hir::TyTup(ref tys) => ty_queue.extend(tys.iter().map(|ty| &**ty)), + _ => {} + } + } + new_ty + } + + fn rebuild_ty(&self, + from: P, + to: P) + -> P { + + fn build_to(from: P, + to: &mut Option>) + -> P { + if Some(from.id) == to.as_ref().map(|ty| ty.id) { + return to.take().expect("`to` type found more than once during rebuild"); + } + from.map(|hir::Ty {id, node, span}| { + let new_node = match node { + hir::TyRptr(lifetime, mut_ty) => { + hir::TyRptr(lifetime, hir::MutTy { + mutbl: mut_ty.mutbl, + ty: build_to(mut_ty.ty, to), + }) + } + hir::TyPtr(mut_ty) => { + hir::TyPtr(hir::MutTy { + mutbl: mut_ty.mutbl, + ty: build_to(mut_ty.ty, to), + }) + } + hir::TyVec(ty) => hir::TyVec(build_to(ty, to)), + hir::TyFixedLengthVec(ty, e) => { + hir::TyFixedLengthVec(build_to(ty, to), e) + } + hir::TyTup(tys) => { + hir::TyTup(tys.into_iter().map(|ty| build_to(ty, to)).collect()) + } + other => other + }; + hir::Ty { id: id, node: new_node, span: span } + }) + } + + build_to(from, &mut Some(to)) + } + + fn rebuild_path(&self, + rebuild_info: RebuildPathInfo, + lifetime: hir::Lifetime) + -> hir::Path + { + let RebuildPathInfo { + path, + indexes, + expected, + anon_nums, + region_names, + } = rebuild_info; + + let last_seg = path.segments.last().unwrap(); + let new_parameters = match last_seg.parameters { + hir::ParenthesizedParameters(..) => { + last_seg.parameters.clone() + } + + hir::AngleBracketedParameters(ref data) => { + let mut new_lts = Vec::new(); + if data.lifetimes.is_empty() { + // traverse once to see if there's a need to insert lifetime + let need_insert = (0..expected).any(|i| { + indexes.contains(&i) + }); + if need_insert { + for i in 0..expected { + if indexes.contains(&i) { + new_lts.push(lifetime); + } else { + new_lts.push(self.life_giver.give_lifetime()); + } + } + } + } else { + for (i, lt) in data.lifetimes.iter().enumerate() { + if indexes.contains(&(i as u32)) { + new_lts.push(lifetime); + } else { + new_lts.push(*lt); + } + } + } + let new_types = data.types.iter().map(|t| { + self.rebuild_arg_ty_or_output(&t, lifetime, anon_nums, region_names) + }).collect(); + let new_bindings = data.bindings.iter().map(|b| { + hir::TypeBinding { + id: b.id, + name: b.name, + ty: self.rebuild_arg_ty_or_output(&b.ty, + lifetime, + anon_nums, + region_names), + span: b.span + } + }).collect(); + hir::AngleBracketedParameters(hir::AngleBracketedParameterData { + lifetimes: new_lts.into(), + types: new_types, + bindings: new_bindings, + }) + } + }; + let new_seg = hir::PathSegment { + identifier: last_seg.identifier, + parameters: new_parameters + }; + let mut new_segs = Vec::new(); + new_segs.extend_from_slice(path.segments.split_last().unwrap().1); + new_segs.push(new_seg); + hir::Path { + span: path.span, + global: path.global, + segments: new_segs.into() + } + } +} + +impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { + fn give_expl_lifetime_param(&self, + err: &mut DiagnosticBuilder, + decl: &hir::FnDecl, + unsafety: hir::Unsafety, + constness: hir::Constness, + name: ast::Name, + opt_explicit_self: Option<&hir::ExplicitSelf_>, + generics: &hir::Generics, + span: Span) { + let suggested_fn = pprust::fun_to_string(decl, unsafety, constness, name, + opt_explicit_self, generics); + let msg = format!("consider using an explicit lifetime \ + parameter as shown: {}", suggested_fn); + err.span_help(span, &msg[..]); + } + + fn report_inference_failure(&self, + var_origin: RegionVariableOrigin) + -> DiagnosticBuilder<'tcx> { + let br_string = |br: ty::BoundRegion| { + let mut s = br.to_string(); + if !s.is_empty() { + s.push_str(" "); + } + s + }; + let var_description = match var_origin { + infer::MiscVariable(_) => "".to_string(), + infer::PatternRegion(_) => " for pattern".to_string(), + infer::AddrOfRegion(_) => " for borrow expression".to_string(), + infer::Autoref(_) => " for autoref".to_string(), + infer::Coercion(_) => " for automatic coercion".to_string(), + infer::LateBoundRegion(_, br, infer::FnCall) => { + format!(" for lifetime parameter {}in function call", + br_string(br)) + } + infer::LateBoundRegion(_, br, infer::HigherRankedType) => { + format!(" for lifetime parameter {}in generic type", br_string(br)) + } + infer::LateBoundRegion(_, br, infer::AssocTypeProjection(type_name)) => { + format!(" for lifetime parameter {}in trait containing associated type `{}`", + br_string(br), type_name) + } + infer::EarlyBoundRegion(_, name) => { + format!(" for lifetime parameter `{}`", + name) + } + infer::BoundRegionInCoherence(name) => { + format!(" for lifetime parameter `{}` in coherence check", + name) + } + infer::UpvarRegion(ref upvar_id, _) => { + format!(" for capture of `{}` by closure", + self.tcx.local_var_name_str(upvar_id.var_id).to_string()) + } + }; + + struct_span_err!(self.tcx.sess, var_origin.span(), E0495, + "cannot infer an appropriate lifetime{} \ + due to conflicting requirements", + var_description) + } + + fn note_region_origin(&self, err: &mut DiagnosticBuilder, origin: &SubregionOrigin<'tcx>) { + match *origin { + infer::Subtype(ref trace) => { + let desc = match trace.origin { + TypeOrigin::Misc(_) => { + "types are compatible" + } + TypeOrigin::MethodCompatCheck(_) => { + "method type is compatible with trait" + } + TypeOrigin::ExprAssignable(_) => { + "expression is assignable" + } + TypeOrigin::RelateTraitRefs(_) => { + "traits are compatible" + } + TypeOrigin::RelateSelfType(_) => { + "self type matches impl self type" + } + TypeOrigin::RelateOutputImplTypes(_) => { + "trait type parameters matches those \ + specified on the impl" + } + TypeOrigin::MatchExpressionArm(_, _, _) => { + "match arms have compatible types" + } + TypeOrigin::IfExpression(_) => { + "if and else have compatible types" + } + TypeOrigin::IfExpressionWithNoElse(_) => { + "if may be missing an else clause" + } + TypeOrigin::RangeExpression(_) => { + "start and end of range have compatible types" + } + TypeOrigin::EquatePredicate(_) => { + "equality where clause is satisfied" + } + }; + + match self.values_str(&trace.values) { + Some(values_str) => { + err.span_note( + trace.origin.span(), + &format!("...so that {} ({})", + desc, values_str)); + } + None => { + // Really should avoid printing this error at + // all, since it is derived, but that would + // require more refactoring than I feel like + // doing right now. - nmatsakis + err.span_note( + trace.origin.span(), + &format!("...so that {}", desc)); + } + } + } + infer::Reborrow(span) => { + err.span_note( + span, + "...so that reference does not outlive \ + borrowed content"); + } + infer::ReborrowUpvar(span, ref upvar_id) => { + err.span_note( + span, + &format!( + "...so that closure can access `{}`", + self.tcx.local_var_name_str(upvar_id.var_id) + .to_string())); + } + infer::InfStackClosure(span) => { + err.span_note( + span, + "...so that closure does not outlive its stack frame"); + } + infer::InvokeClosure(span) => { + err.span_note( + span, + "...so that closure is not invoked outside its lifetime"); + } + infer::DerefPointer(span) => { + err.span_note( + span, + "...so that pointer is not dereferenced \ + outside its lifetime"); + } + infer::FreeVariable(span, id) => { + err.span_note( + span, + &format!("...so that captured variable `{}` \ + does not outlive the enclosing closure", + self.tcx.local_var_name_str(id))); + } + infer::IndexSlice(span) => { + err.span_note( + span, + "...so that slice is not indexed outside the lifetime"); + } + infer::RelateObjectBound(span) => { + err.span_note( + span, + "...so that it can be closed over into an object"); + } + infer::CallRcvr(span) => { + err.span_note( + span, + "...so that method receiver is valid for the method call"); + } + infer::CallArg(span) => { + err.span_note( + span, + "...so that argument is valid for the call"); + } + infer::CallReturn(span) => { + err.span_note( + span, + "...so that return value is valid for the call"); + } + infer::Operand(span) => { + err.span_note( + span, + "...so that operand is valid for operation"); + } + infer::AddrOf(span) => { + err.span_note( + span, + "...so that reference is valid \ + at the time of borrow"); + } + infer::AutoBorrow(span) => { + err.span_note( + span, + "...so that auto-reference is valid \ + at the time of borrow"); + } + infer::ExprTypeIsNotInScope(t, span) => { + err.span_note( + span, + &format!("...so type `{}` of expression is valid during the \ + expression", + self.ty_to_string(t))); + } + infer::BindingTypeIsNotValidAtDecl(span) => { + err.span_note( + span, + "...so that variable is valid at time of its declaration"); + } + infer::ParameterInScope(_, span) => { + err.span_note( + span, + "...so that a type/lifetime parameter is in scope here"); + } + infer::DataBorrowed(ty, span) => { + err.span_note( + span, + &format!("...so that the type `{}` is not borrowed for too long", + self.ty_to_string(ty))); + } + infer::ReferenceOutlivesReferent(ty, span) => { + err.span_note( + span, + &format!("...so that the reference type `{}` \ + does not outlive the data it points at", + self.ty_to_string(ty))); + } + infer::RelateParamBound(span, t) => { + err.span_note( + span, + &format!("...so that the type `{}` \ + will meet its required lifetime bounds", + self.ty_to_string(t))); + } + infer::RelateDefaultParamBound(span, t) => { + err.span_note( + span, + &format!("...so that type parameter \ + instantiated with `{}`, \ + will meet its declared lifetime bounds", + self.ty_to_string(t))); + } + infer::RelateRegionParamBound(span) => { + err.span_note( + span, + "...so that the declared lifetime parameter bounds \ + are satisfied"); + } + infer::SafeDestructor(span) => { + err.span_note( + span, + "...so that references are valid when the destructor \ + runs"); + } + } + } +} + +pub trait Resolvable<'tcx> { + fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) -> Self; +} + +impl<'tcx> Resolvable<'tcx> for Ty<'tcx> { + fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) -> Ty<'tcx> { + infcx.resolve_type_vars_if_possible(self) + } +} + +impl<'tcx> Resolvable<'tcx> for ty::TraitRef<'tcx> { + fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) + -> ty::TraitRef<'tcx> { + infcx.resolve_type_vars_if_possible(self) + } +} + +impl<'tcx> Resolvable<'tcx> for ty::PolyTraitRef<'tcx> { + fn resolve<'a>(&self, + infcx: &InferCtxt<'a, 'tcx>) + -> ty::PolyTraitRef<'tcx> + { + infcx.resolve_type_vars_if_possible(self) + } +} + +fn lifetimes_in_scope(tcx: &TyCtxt, + scope_id: ast::NodeId) + -> Vec { + let mut taken = Vec::new(); + let parent = tcx.map.get_parent(scope_id); + let method_id_opt = match tcx.map.find(parent) { + Some(node) => match node { + ast_map::NodeItem(item) => match item.node { + hir::ItemFn(_, _, _, _, ref gen, _) => { + taken.extend_from_slice(&gen.lifetimes); + None + }, + _ => None + }, + ast_map::NodeImplItem(ii) => { + match ii.node { + hir::ImplItemKind::Method(ref sig, _) => { + taken.extend_from_slice(&sig.generics.lifetimes); + Some(ii.id) + } + _ => None, + } + } + _ => None + }, + None => None + }; + if method_id_opt.is_some() { + let method_id = method_id_opt.unwrap(); + let parent = tcx.map.get_parent(method_id); + match tcx.map.find(parent) { + Some(node) => match node { + ast_map::NodeItem(item) => match item.node { + hir::ItemImpl(_, _, ref gen, _, _, _) => { + taken.extend_from_slice(&gen.lifetimes); + } + _ => () + }, + _ => () + }, + None => () + } + } + return taken; +} + +// LifeGiver is responsible for generating fresh lifetime names +struct LifeGiver { + taken: HashSet, + counter: Cell, + generated: RefCell>, +} + +impl LifeGiver { + fn with_taken(taken: &[hir::LifetimeDef]) -> LifeGiver { + let mut taken_ = HashSet::new(); + for lt in taken { + let lt_name = lt.lifetime.name.to_string(); + taken_.insert(lt_name); + } + LifeGiver { + taken: taken_, + counter: Cell::new(0), + generated: RefCell::new(Vec::new()), + } + } + + fn inc_counter(&self) { + let c = self.counter.get(); + self.counter.set(c+1); + } + + fn give_lifetime(&self) -> hir::Lifetime { + let lifetime; + loop { + let mut s = String::from("'"); + s.push_str(&num_to_string(self.counter.get())); + if !self.taken.contains(&s) { + lifetime = name_to_dummy_lifetime(token::intern(&s[..])); + self.generated.borrow_mut().push(lifetime); + break; + } + self.inc_counter(); + } + self.inc_counter(); + return lifetime; + + // 0 .. 25 generates a .. z, 26 .. 51 generates aa .. zz, and so on + fn num_to_string(counter: usize) -> String { + let mut s = String::new(); + let (n, r) = (counter/26 + 1, counter % 26); + let letter: char = from_u32((r+97) as u32).unwrap(); + for _ in 0..n { + s.push(letter); + } + s + } + } + + fn get_generated_lifetimes(&self) -> Vec { + self.generated.borrow().clone() + } +} + +fn name_to_dummy_lifetime(name: ast::Name) -> hir::Lifetime { + hir::Lifetime { id: ast::DUMMY_NODE_ID, + span: codemap::DUMMY_SP, + name: name } +} diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs new file mode 100644 index 00000000000..352733a595d --- /dev/null +++ b/src/librustc/infer/freshen.rs @@ -0,0 +1,177 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Freshening is the process of replacing unknown variables with fresh types. The idea is that +//! the type, after freshening, contains no inference variables but instead contains either a +//! value for each variable or fresh "arbitrary" types wherever a variable would have been. +//! +//! Freshening is used primarily to get a good type for inserting into a cache. The result +//! summarizes what the type inferencer knows "so far". The primary place it is used right now is +//! in the trait matching algorithm, which needs to be able to cache whether an `impl` self type +//! matches some other type X -- *without* affecting `X`. That means if that if the type `X` is in +//! fact an unbound type variable, we want the match to be regarded as ambiguous, because depending +//! on what type that type variable is ultimately assigned, the match may or may not succeed. +//! +//! Note that you should be careful not to allow the output of freshening to leak to the user in +//! error messages or in any other form. Freshening is only really useful as an internal detail. +//! +//! __An important detail concerning regions.__ The freshener also replaces *all* regions with +//! 'static. The reason behind this is that, in general, we do not take region relationships into +//! account when making type-overloaded decisions. This is important because of the design of the +//! region inferencer, which is not based on unification but rather on accumulating and then +//! solving a set of constraints. In contrast, the type inferencer assigns a value to each type +//! variable only once, and it does so as soon as it can, so it is reasonable to ask what the type +//! inferencer knows "so far". + +use ty::{self, Ty, TyCtxt, TypeFoldable}; +use ty::fold::TypeFolder; +use std::collections::hash_map::{self, Entry}; + +use super::InferCtxt; +use super::unify_key::ToType; + +pub struct TypeFreshener<'a, 'tcx:'a> { + infcx: &'a InferCtxt<'a, 'tcx>, + freshen_count: u32, + freshen_map: hash_map::HashMap>, +} + +impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { + pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> TypeFreshener<'a, 'tcx> { + TypeFreshener { + infcx: infcx, + freshen_count: 0, + freshen_map: hash_map::HashMap::new(), + } + } + + fn freshen(&mut self, + opt_ty: Option>, + key: ty::InferTy, + freshener: F) + -> Ty<'tcx> where + F: FnOnce(u32) -> ty::InferTy, + { + match opt_ty { + Some(ty) => { return ty.fold_with(self); } + None => { } + } + + match self.freshen_map.entry(key) { + Entry::Occupied(entry) => *entry.get(), + Entry::Vacant(entry) => { + let index = self.freshen_count; + self.freshen_count += 1; + let t = self.infcx.tcx.mk_infer(freshener(index)); + entry.insert(t); + t + } + } + } +} + +impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { + fn tcx<'b>(&'b self) -> &'b TyCtxt<'tcx> { + self.infcx.tcx + } + + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + match r { + ty::ReEarlyBound(..) | + ty::ReLateBound(..) => { + // leave bound regions alone + r + } + + ty::ReStatic | + ty::ReFree(_) | + ty::ReScope(_) | + ty::ReVar(_) | + ty::ReSkolemized(..) | + ty::ReEmpty => { + // replace all free regions with 'static + ty::ReStatic + } + } + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + if !t.needs_infer() && !t.has_erasable_regions() { + return t; + } + + let tcx = self.infcx.tcx; + + match t.sty { + ty::TyInfer(ty::TyVar(v)) => { + let opt_ty = self.infcx.type_variables.borrow_mut().probe(v); + self.freshen( + opt_ty, + ty::TyVar(v), + ty::FreshTy) + } + + ty::TyInfer(ty::IntVar(v)) => { + self.freshen( + self.infcx.int_unification_table.borrow_mut() + .probe(v) + .map(|v| v.to_type(tcx)), + ty::IntVar(v), + ty::FreshIntTy) + } + + ty::TyInfer(ty::FloatVar(v)) => { + self.freshen( + self.infcx.float_unification_table.borrow_mut() + .probe(v) + .map(|v| v.to_type(tcx)), + ty::FloatVar(v), + ty::FreshFloatTy) + } + + ty::TyInfer(ty::FreshTy(c)) | + ty::TyInfer(ty::FreshIntTy(c)) | + ty::TyInfer(ty::FreshFloatTy(c)) => { + if c >= self.freshen_count { + tcx.sess.bug( + &format!("Encountered a freshend type with id {} \ + but our counter is only at {}", + c, + self.freshen_count)); + } + t + } + + ty::TyBool | + ty::TyChar | + ty::TyInt(..) | + ty::TyUint(..) | + ty::TyFloat(..) | + ty::TyEnum(..) | + ty::TyBox(..) | + ty::TyStr | + ty::TyError | + ty::TyArray(..) | + ty::TySlice(..) | + ty::TyRawPtr(..) | + ty::TyRef(..) | + ty::TyFnDef(..) | + ty::TyFnPtr(_) | + ty::TyTrait(..) | + ty::TyStruct(..) | + ty::TyClosure(..) | + ty::TyTuple(..) | + ty::TyProjection(..) | + ty::TyParam(..) => { + t.super_fold_with(self) + } + } + } +} diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs new file mode 100644 index 00000000000..235428a6898 --- /dev/null +++ b/src/librustc/infer/glb.rs @@ -0,0 +1,85 @@ +// Copyright 2012 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::combine::CombineFields; +use super::higher_ranked::HigherRankedRelations; +use super::InferCtxt; +use super::lattice::{self, LatticeDir}; +use super::Subtype; + +use ty::{self, Ty, TyCtxt}; +use ty::relate::{Relate, RelateResult, TypeRelation}; + +/// "Greatest lower bound" (common subtype) +pub struct Glb<'a, 'tcx: 'a> { + fields: CombineFields<'a, 'tcx> +} + +impl<'a, 'tcx> Glb<'a, 'tcx> { + pub fn new(fields: CombineFields<'a, 'tcx>) -> Glb<'a, 'tcx> { + Glb { fields: fields } + } +} + +impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Glb<'a, 'tcx> { + fn tag(&self) -> &'static str { "Glb" } + + fn tcx(&self) -> &'a TyCtxt<'tcx> { self.fields.tcx() } + + fn a_is_expected(&self) -> bool { self.fields.a_is_expected } + + fn relate_with_variance>(&mut self, + variance: ty::Variance, + a: &T, + b: &T) + -> RelateResult<'tcx, T> + { + match variance { + ty::Invariant => self.fields.equate().relate(a, b), + ty::Covariant => self.relate(a, b), + ty::Bivariant => self.fields.bivariate().relate(a, b), + ty::Contravariant => self.fields.lub().relate(a, b), + } + } + + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + lattice::super_lattice_tys(self, a, b) + } + + fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> { + debug!("{}.regions({:?}, {:?})", + self.tag(), + a, + b); + + let origin = Subtype(self.fields.trace.clone()); + Ok(self.fields.infcx.region_vars.glb_regions(origin, a, b)) + } + + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where T: Relate<'a, 'tcx> + { + self.fields.higher_ranked_glb(a, b) + } +} + +impl<'a, 'tcx> LatticeDir<'a,'tcx> for Glb<'a, 'tcx> { + fn infcx(&self) -> &'a InferCtxt<'a,'tcx> { + self.fields.infcx + } + + fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { + let mut sub = self.fields.sub(); + sub.relate(&v, &a)?; + sub.relate(&v, &b)?; + Ok(()) + } +} diff --git a/src/librustc/infer/higher_ranked/README.md b/src/librustc/infer/higher_ranked/README.md new file mode 100644 index 00000000000..57665b6d939 --- /dev/null +++ b/src/librustc/infer/higher_ranked/README.md @@ -0,0 +1,403 @@ +# Skolemization and functions + +One of the trickiest and most subtle aspects of regions is dealing +with higher-ranked things which include bound region variables, such +as function types. I strongly suggest that if you want to understand +the situation, you read this paper (which is, admittedly, very long, +but you don't have to read the whole thing): + +http://research.microsoft.com/en-us/um/people/simonpj/papers/higher-rank/ + +Although my explanation will never compete with SPJ's (for one thing, +his is approximately 100 pages), I will attempt to explain the basic +problem and also how we solve it. Note that the paper only discusses +subtyping, not the computation of LUB/GLB. + +The problem we are addressing is that there is a kind of subtyping +between functions with bound region parameters. Consider, for +example, whether the following relation holds: + + for<'a> fn(&'a isize) <: for<'b> fn(&'b isize)? (Yes, a => b) + +The answer is that of course it does. These two types are basically +the same, except that in one we used the name `a` and one we used +the name `b`. + +In the examples that follow, it becomes very important to know whether +a lifetime is bound in a function type (that is, is a lifetime +parameter) or appears free (is defined in some outer scope). +Therefore, from now on I will always write the bindings explicitly, +using the Rust syntax `for<'a> fn(&'a isize)` to indicate that `a` is a +lifetime parameter. + +Now let's consider two more function types. Here, we assume that the +`'b` lifetime is defined somewhere outside and hence is not a lifetime +parameter bound by the function type (it "appears free"): + + for<'a> fn(&'a isize) <: fn(&'b isize)? (Yes, a => b) + +This subtyping relation does in fact hold. To see why, you have to +consider what subtyping means. One way to look at `T1 <: T2` is to +say that it means that it is always ok to treat an instance of `T1` as +if it had the type `T2`. So, with our functions, it is always ok to +treat a function that can take pointers with any lifetime as if it +were a function that can only take a pointer with the specific +lifetime `'b`. After all, `'b` is a lifetime, after all, and +the function can take values of any lifetime. + +You can also look at subtyping as the *is a* relationship. This amounts +to the same thing: a function that accepts pointers with any lifetime +*is a* function that accepts pointers with some specific lifetime. + +So, what if we reverse the order of the two function types, like this: + + fn(&'b isize) <: for<'a> fn(&'a isize)? (No) + +Does the subtyping relationship still hold? The answer of course is +no. In this case, the function accepts *only the lifetime `'b`*, +so it is not reasonable to treat it as if it were a function that +accepted any lifetime. + +What about these two examples: + + for<'a,'b> fn(&'a isize, &'b isize) <: for<'a> fn(&'a isize, &'a isize)? (Yes) + for<'a> fn(&'a isize, &'a isize) <: for<'a,'b> fn(&'a isize, &'b isize)? (No) + +Here, it is true that functions which take two pointers with any two +lifetimes can be treated as if they only accepted two pointers with +the same lifetime, but not the reverse. + +## The algorithm + +Here is the algorithm we use to perform the subtyping check: + +1. Replace all bound regions in the subtype with new variables +2. Replace all bound regions in the supertype with skolemized + equivalents. A "skolemized" region is just a new fresh region + name. +3. Check that the parameter and return types match as normal +4. Ensure that no skolemized regions 'leak' into region variables + visible from "the outside" + +Let's walk through some examples and see how this algorithm plays out. + +#### First example + +We'll start with the first example, which was: + + 1. for<'a> fn(&'a T) <: for<'b> fn(&'b T)? Yes: a -> b + +After steps 1 and 2 of the algorithm we will have replaced the types +like so: + + 1. fn(&'A T) <: fn(&'x T)? + +Here the upper case `&A` indicates a *region variable*, that is, a +region whose value is being inferred by the system. I also replaced +`&b` with `&x`---I'll use letters late in the alphabet (`x`, `y`, `z`) +to indicate skolemized region names. We can assume they don't appear +elsewhere. Note that neither the sub- nor the supertype bind any +region names anymore (as indicated by the absence of `<` and `>`). + +The next step is to check that the parameter types match. Because +parameters are contravariant, this means that we check whether: + + &'x T <: &'A T + +Region pointers are contravariant so this implies that + + &A <= &x + +must hold, where `<=` is the subregion relationship. Processing +*this* constrain simply adds a constraint into our graph that `&A <= +&x` and is considered successful (it can, for example, be satisfied by +choosing the value `&x` for `&A`). + +So far we have encountered no error, so the subtype check succeeds. + +#### The third example + +Now let's look first at the third example, which was: + + 3. fn(&'a T) <: for<'b> fn(&'b T)? No! + +After steps 1 and 2 of the algorithm we will have replaced the types +like so: + + 3. fn(&'a T) <: fn(&'x T)? + +This looks pretty much the same as before, except that on the LHS +`'a` was not bound, and hence was left as-is and not replaced with +a variable. The next step is again to check that the parameter types +match. This will ultimately require (as before) that `'a` <= `&x` +must hold: but this does not hold. `self` and `x` are both distinct +free regions. So the subtype check fails. + +#### Checking for skolemization leaks + +You may be wondering about that mysterious last step in the algorithm. +So far it has not been relevant. The purpose of that last step is to +catch something like *this*: + + for<'a> fn() -> fn(&'a T) <: fn() -> for<'b> fn(&'b T)? No. + +Here the function types are the same but for where the binding occurs. +The subtype returns a function that expects a value in precisely one +region. The supertype returns a function that expects a value in any +region. If we allow an instance of the subtype to be used where the +supertype is expected, then, someone could call the fn and think that +the return value has type `fn(&'b T)` when it really has type +`fn(&'a T)` (this is case #3, above). Bad. + +So let's step through what happens when we perform this subtype check. +We first replace the bound regions in the subtype (the supertype has +no bound regions). This gives us: + + fn() -> fn(&'A T) <: fn() -> for<'b> fn(&'b T)? + +Now we compare the return types, which are covariant, and hence we have: + + fn(&'A T) <: for<'b> fn(&'b T)? + +Here we skolemize the bound region in the supertype to yield: + + fn(&'A T) <: fn(&'x T)? + +And then proceed to compare the argument types: + + &'x T <: &'A T + 'A <= 'x + +Finally, this is where it gets interesting! This is where an error +*should* be reported. But in fact this will not happen. The reason why +is that `A` is a variable: we will infer that its value is the fresh +region `x` and think that everything is happy. In fact, this behavior +is *necessary*, it was key to the first example we walked through. + +The difference between this example and the first one is that the variable +`A` already existed at the point where the skolemization occurred. In +the first example, you had two functions: + + for<'a> fn(&'a T) <: for<'b> fn(&'b T) + +and hence `&A` and `&x` were created "together". In general, the +intention of the skolemized names is that they are supposed to be +fresh names that could never be equal to anything from the outside. +But when inference comes into play, we might not be respecting this +rule. + +So the way we solve this is to add a fourth step that examines the +constraints that refer to skolemized names. Basically, consider a +non-directed version of the constraint graph. Let `Tainted(x)` be the +set of all things reachable from a skolemized variable `x`. +`Tainted(x)` should not contain any regions that existed before the +step at which the skolemization was performed. So this case here +would fail because `&x` was created alone, but is relatable to `&A`. + +## Computing the LUB and GLB + +The paper I pointed you at is written for Haskell. It does not +therefore considering subtyping and in particular does not consider +LUB or GLB computation. We have to consider this. Here is the +algorithm I implemented. + +First though, let's discuss what we are trying to compute in more +detail. The LUB is basically the "common supertype" and the GLB is +"common subtype"; one catch is that the LUB should be the +*most-specific* common supertype and the GLB should be *most general* +common subtype (as opposed to any common supertype or any common +subtype). + +Anyway, to help clarify, here is a table containing some function +pairs and their LUB/GLB (for conciseness, in this table, I'm just +including the lifetimes here, not the rest of the types, and I'm +writing `fn<>` instead of `for<> fn`): + +``` +Type 1 Type 2 LUB GLB +fn<'a>('a) fn('X) fn('X) fn<'a>('a) +fn('a) fn('X) -- fn<'a>('a) +fn<'a,'b>('a, 'b) fn<'x>('x, 'x) fn<'a>('a, 'a) fn<'a,'b>('a, 'b) +fn<'a,'b>('a, 'b, 'a) fn<'x,'y>('x, 'y, 'y) fn<'a>('a, 'a, 'a) fn<'a,'b,'c>('a,'b,'c) +``` + +### Conventions + +I use lower-case letters (e.g., `&a`) for bound regions and upper-case +letters for free regions (`&A`). Region variables written with a +dollar-sign (e.g., `$a`). I will try to remember to enumerate the +bound-regions on the fn type as well (e.g., `for<'a> fn(&a)`). + +### High-level summary + +Both the LUB and the GLB algorithms work in a similar fashion. They +begin by replacing all bound regions (on both sides) with fresh region +inference variables. Therefore, both functions are converted to types +that contain only free regions. We can then compute the LUB/GLB in a +straightforward way, as described in `combine.rs`. This results in an +interim type T. The algorithms then examine the regions that appear +in T and try to, in some cases, replace them with bound regions to +yield the final result. + +To decide whether to replace a region `R` that appears in `T` with +a bound region, the algorithms make use of two bits of +information. First is a set `V` that contains all region +variables created as part of the LUB/GLB computation (roughly; see +`region_vars_confined_to_snapshot()` for full details). `V` will +contain the region variables created to replace the bound regions +in the input types, but it also contains 'intermediate' variables +created to represent the LUB/GLB of individual regions. +Basically, when asked to compute the LUB/GLB of a region variable +with another region, the inferencer cannot oblige immediately +since the values of that variables are not known. Therefore, it +creates a new variable that is related to the two regions. For +example, the LUB of two variables `$x` and `$y` is a fresh +variable `$z` that is constrained such that `$x <= $z` and `$y <= +$z`. So `V` will contain these intermediate variables as well. + +The other important factor in deciding how to replace a region in T is +the function `Tainted($r)` which, for a region variable, identifies +all regions that the region variable is related to in some way +(`Tainted()` made an appearance in the subtype computation as well). + +### LUB + +The LUB algorithm proceeds in three steps: + +1. Replace all bound regions (on both sides) with fresh region + inference variables. +2. Compute the LUB "as normal", meaning compute the GLB of each + pair of argument types and the LUB of the return types and + so forth. Combine those to a new function type `F`. +3. Replace each region `R` that appears in `F` as follows: + - Let `V` be the set of variables created during the LUB + computational steps 1 and 2, as described in the previous section. + - If `R` is not in `V`, replace `R` with itself. + - If `Tainted(R)` contains a region that is not in `V`, + replace `R` with itself. + - Otherwise, select the earliest variable in `Tainted(R)` that originates + from the left-hand side and replace `R` with the bound region that + this variable was a replacement for. + +So, let's work through the simplest example: `fn(&A)` and `for<'a> fn(&a)`. +In this case, `&a` will be replaced with `$a` and the interim LUB type +`fn($b)` will be computed, where `$b=GLB(&A,$a)`. Therefore, `V = +{$a, $b}` and `Tainted($b) = { $b, $a, &A }`. When we go to replace +`$b`, we find that since `&A \in Tainted($b)` is not a member of `V`, +we leave `$b` as is. When region inference happens, `$b` will be +resolved to `&A`, as we wanted. + +Let's look at a more complex one: `fn(&a, &b)` and `fn(&x, &x)`. In +this case, we'll end up with a (pre-replacement) LUB type of `fn(&g, +&h)` and a graph that looks like: + +``` + $a $b *--$x + \ \ / / + \ $h-* / + $g-----------* +``` + +Here `$g` and `$h` are fresh variables that are created to represent +the LUB/GLB of things requiring inference. This means that `V` and +`Tainted` will look like: + +``` +V = {$a, $b, $g, $h, $x} +Tainted($g) = Tainted($h) = { $a, $b, $h, $g, $x } +``` + +Therefore we replace both `$g` and `$h` with `$a`, and end up +with the type `fn(&a, &a)`. + +### GLB + +The procedure for computing the GLB is similar. The difference lies +in computing the replacements for the various variables. For each +region `R` that appears in the type `F`, we again compute `Tainted(R)` +and examine the results: + +1. If `R` is not in `V`, it is not replaced. +2. Else, if `Tainted(R)` contains only variables in `V`, and it + contains exactly one variable from the LHS and one variable from + the RHS, then `R` can be mapped to the bound version of the + variable from the LHS. +3. Else, if `Tainted(R)` contains no variable from the LHS and no + variable from the RHS, then `R` can be mapped to itself. +4. Else, `R` is mapped to a fresh bound variable. + +These rules are pretty complex. Let's look at some examples to see +how they play out. + +Out first example was `fn(&a)` and `fn(&X)`. In this case, `&a` will +be replaced with `$a` and we will ultimately compute a +(pre-replacement) GLB type of `fn($g)` where `$g=LUB($a,&X)`. +Therefore, `V={$a,$g}` and `Tainted($g)={$g,$a,&X}. To find the +replacement for `$g` we consult the rules above: +- Rule (1) does not apply because `$g \in V` +- Rule (2) does not apply because `&X \in Tainted($g)` +- Rule (3) does not apply because `$a \in Tainted($g)` +- Hence, by rule (4), we replace `$g` with a fresh bound variable `&z`. +So our final result is `fn(&z)`, which is correct. + +The next example is `fn(&A)` and `fn(&Z)`. In this case, we will again +have a (pre-replacement) GLB of `fn(&g)`, where `$g = LUB(&A,&Z)`. +Therefore, `V={$g}` and `Tainted($g) = {$g, &A, &Z}`. In this case, +by rule (3), `$g` is mapped to itself, and hence the result is +`fn($g)`. This result is correct (in this case, at least), but it is +indicative of a case that *can* lead us into concluding that there is +no GLB when in fact a GLB does exist. See the section "Questionable +Results" below for more details. + +The next example is `fn(&a, &b)` and `fn(&c, &c)`. In this case, as +before, we'll end up with `F=fn($g, $h)` where `Tainted($g) = +Tainted($h) = {$g, $h, $a, $b, $c}`. Only rule (4) applies and hence +we'll select fresh bound variables `y` and `z` and wind up with +`fn(&y, &z)`. + +For the last example, let's consider what may seem trivial, but is +not: `fn(&a, &a)` and `fn(&b, &b)`. In this case, we'll get `F=fn($g, +$h)` where `Tainted($g) = {$g, $a, $x}` and `Tainted($h) = {$h, $a, +$x}`. Both of these sets contain exactly one bound variable from each +side, so we'll map them both to `&a`, resulting in `fn(&a, &a)`, which +is the desired result. + +### Shortcomings and correctness + +You may be wondering whether this algorithm is correct. The answer is +"sort of". There are definitely cases where they fail to compute a +result even though a correct result exists. I believe, though, that +if they succeed, then the result is valid, and I will attempt to +convince you. The basic argument is that the "pre-replacement" step +computes a set of constraints. The replacements, then, attempt to +satisfy those constraints, using bound identifiers where needed. + +For now I will briefly go over the cases for LUB/GLB and identify +their intent: + +- LUB: + - The region variables that are substituted in place of bound regions + are intended to collect constraints on those bound regions. + - If Tainted(R) contains only values in V, then this region is unconstrained + and can therefore be generalized, otherwise it cannot. +- GLB: + - The region variables that are substituted in place of bound regions + are intended to collect constraints on those bound regions. + - If Tainted(R) contains exactly one variable from each side, and + only variables in V, that indicates that those two bound regions + must be equated. + - Otherwise, if Tainted(R) references any variables from left or right + side, then it is trying to combine a bound region with a free one or + multiple bound regions, so we need to select fresh bound regions. + +Sorry this is more of a shorthand to myself. I will try to write up something +more convincing in the future. + +#### Where are the algorithms wrong? + +- The pre-replacement computation can fail even though using a + bound-region would have succeeded. +- We will compute GLB(fn(fn($a)), fn(fn($b))) as fn($c) where $c is the + GLB of $a and $b. But if inference finds that $a and $b must be mapped + to regions without a GLB, then this is effectively a failure to compute + the GLB. However, the result `fn<$c>(fn($c))` is a valid GLB. diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs new file mode 100644 index 00000000000..db4ee17bafb --- /dev/null +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -0,0 +1,614 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Helper routines for higher-ranked things. See the `doc` module at +//! the end of the file for details. + +use super::{CombinedSnapshot, InferCtxt, HigherRankedType, SkolemizationMap}; +use super::combine::CombineFields; + +use ty::{self, TyCtxt, Binder, TypeFoldable}; +use ty::error::TypeError; +use ty::relate::{Relate, RelateResult, TypeRelation}; +use syntax::codemap::Span; +use util::nodemap::{FnvHashMap, FnvHashSet}; + +pub trait HigherRankedRelations<'a,'tcx> { + fn higher_ranked_sub(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> + where T: Relate<'a,'tcx>; + + fn higher_ranked_lub(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> + where T: Relate<'a,'tcx>; + + fn higher_ranked_glb(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> + where T: Relate<'a,'tcx>; +} + +trait InferCtxtExt { + fn tainted_regions(&self, snapshot: &CombinedSnapshot, r: ty::Region) -> Vec; + + fn region_vars_confined_to_snapshot(&self, + snapshot: &CombinedSnapshot) + -> Vec; +} + +impl<'a,'tcx> HigherRankedRelations<'a,'tcx> for CombineFields<'a,'tcx> { + fn higher_ranked_sub(&self, a: &Binder, b: &Binder) + -> RelateResult<'tcx, Binder> + where T: Relate<'a,'tcx> + { + debug!("higher_ranked_sub(a={:?}, b={:?})", + a, b); + + // Rather than checking the subtype relationship between `a` and `b` + // as-is, we need to do some extra work here in order to make sure + // that function subtyping works correctly with respect to regions + // + // Note: this is a subtle algorithm. For a full explanation, + // please see the large comment at the end of the file in the (inlined) module + // `doc`. + + // Start a snapshot so we can examine "all bindings that were + // created as part of this type comparison". + return self.infcx.commit_if_ok(|snapshot| { + // First, we instantiate each bound region in the subtype with a fresh + // region variable. + let (a_prime, _) = + self.infcx.replace_late_bound_regions_with_fresh_var( + self.trace.origin.span(), + HigherRankedType, + a); + + // Second, we instantiate each bound region in the supertype with a + // fresh concrete region. + let (b_prime, skol_map) = + self.infcx.skolemize_late_bound_regions(b, snapshot); + + debug!("a_prime={:?}", a_prime); + debug!("b_prime={:?}", b_prime); + + // Compare types now that bound regions have been replaced. + let result = self.sub().relate(&a_prime, &b_prime)?; + + // Presuming type comparison succeeds, we need to check + // that the skolemized regions do not "leak". + match leak_check(self.infcx, &skol_map, snapshot) { + Ok(()) => { } + Err((skol_br, tainted_region)) => { + if self.a_is_expected { + debug!("Not as polymorphic!"); + return Err(TypeError::RegionsInsufficientlyPolymorphic(skol_br, + tainted_region)); + } else { + debug!("Overly polymorphic!"); + return Err(TypeError::RegionsOverlyPolymorphic(skol_br, + tainted_region)); + } + } + } + + debug!("higher_ranked_sub: OK result={:?}", + result); + + Ok(ty::Binder(result)) + }); + } + + fn higher_ranked_lub(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> + where T: Relate<'a,'tcx> + { + // Start a snapshot so we can examine "all bindings that were + // created as part of this type comparison". + return self.infcx.commit_if_ok(|snapshot| { + // Instantiate each bound region with a fresh region variable. + let span = self.trace.origin.span(); + let (a_with_fresh, a_map) = + self.infcx.replace_late_bound_regions_with_fresh_var( + span, HigherRankedType, a); + let (b_with_fresh, _) = + self.infcx.replace_late_bound_regions_with_fresh_var( + span, HigherRankedType, b); + + // Collect constraints. + let result0 = + self.lub().relate(&a_with_fresh, &b_with_fresh)?; + let result0 = + self.infcx.resolve_type_vars_if_possible(&result0); + debug!("lub result0 = {:?}", result0); + + // Generalize the regions appearing in result0 if possible + let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot); + let span = self.trace.origin.span(); + let result1 = + fold_regions_in( + self.tcx(), + &result0, + |r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn, + &new_vars, &a_map, r)); + + debug!("lub({:?},{:?}) = {:?}", + a, + b, + result1); + + Ok(ty::Binder(result1)) + }); + + fn generalize_region(infcx: &InferCtxt, + span: Span, + snapshot: &CombinedSnapshot, + debruijn: ty::DebruijnIndex, + new_vars: &[ty::RegionVid], + a_map: &FnvHashMap, + r0: ty::Region) + -> ty::Region { + // Regions that pre-dated the LUB computation stay as they are. + if !is_var_in_set(new_vars, r0) { + assert!(!r0.is_bound()); + debug!("generalize_region(r0={:?}): not new variable", r0); + return r0; + } + + let tainted = infcx.tainted_regions(snapshot, r0); + + // Variables created during LUB computation which are + // *related* to regions that pre-date the LUB computation + // stay as they are. + if !tainted.iter().all(|r| is_var_in_set(new_vars, *r)) { + debug!("generalize_region(r0={:?}): \ + non-new-variables found in {:?}", + r0, tainted); + assert!(!r0.is_bound()); + return r0; + } + + // Otherwise, the variable must be associated with at + // least one of the variables representing bound regions + // in both A and B. Replace the variable with the "first" + // bound region from A that we find it to be associated + // with. + for (a_br, a_r) in a_map { + if tainted.iter().any(|x| x == a_r) { + debug!("generalize_region(r0={:?}): \ + replacing with {:?}, tainted={:?}", + r0, *a_br, tainted); + return ty::ReLateBound(debruijn, *a_br); + } + } + + infcx.tcx.sess.span_bug( + span, + &format!("region {:?} is not associated with \ + any bound region from A!", + r0)) + } + } + + fn higher_ranked_glb(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> + where T: Relate<'a,'tcx> + { + debug!("higher_ranked_glb({:?}, {:?})", + a, b); + + // Make a snapshot so we can examine "all bindings that were + // created as part of this type comparison". + return self.infcx.commit_if_ok(|snapshot| { + // Instantiate each bound region with a fresh region variable. + let (a_with_fresh, a_map) = + self.infcx.replace_late_bound_regions_with_fresh_var( + self.trace.origin.span(), HigherRankedType, a); + let (b_with_fresh, b_map) = + self.infcx.replace_late_bound_regions_with_fresh_var( + self.trace.origin.span(), HigherRankedType, b); + let a_vars = var_ids(self, &a_map); + let b_vars = var_ids(self, &b_map); + + // Collect constraints. + let result0 = + self.glb().relate(&a_with_fresh, &b_with_fresh)?; + let result0 = + self.infcx.resolve_type_vars_if_possible(&result0); + debug!("glb result0 = {:?}", result0); + + // Generalize the regions appearing in result0 if possible + let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot); + let span = self.trace.origin.span(); + let result1 = + fold_regions_in( + self.tcx(), + &result0, + |r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn, + &new_vars, + &a_map, &a_vars, &b_vars, + r)); + + debug!("glb({:?},{:?}) = {:?}", + a, + b, + result1); + + Ok(ty::Binder(result1)) + }); + + fn generalize_region(infcx: &InferCtxt, + span: Span, + snapshot: &CombinedSnapshot, + debruijn: ty::DebruijnIndex, + new_vars: &[ty::RegionVid], + a_map: &FnvHashMap, + a_vars: &[ty::RegionVid], + b_vars: &[ty::RegionVid], + r0: ty::Region) -> ty::Region { + if !is_var_in_set(new_vars, r0) { + assert!(!r0.is_bound()); + return r0; + } + + let tainted = infcx.tainted_regions(snapshot, r0); + + let mut a_r = None; + let mut b_r = None; + let mut only_new_vars = true; + for r in &tainted { + if is_var_in_set(a_vars, *r) { + if a_r.is_some() { + return fresh_bound_variable(infcx, debruijn); + } else { + a_r = Some(*r); + } + } else if is_var_in_set(b_vars, *r) { + if b_r.is_some() { + return fresh_bound_variable(infcx, debruijn); + } else { + b_r = Some(*r); + } + } else if !is_var_in_set(new_vars, *r) { + only_new_vars = false; + } + } + + // NB---I do not believe this algorithm computes + // (necessarily) the GLB. As written it can + // spuriously fail. In particular, if there is a case + // like: |fn(&a)| and fn(fn(&b)), where a and b are + // free, it will return fn(&c) where c = GLB(a,b). If + // however this GLB is not defined, then the result is + // an error, even though something like + // "fn(fn(&X))" where X is bound would be a + // subtype of both of those. + // + // The problem is that if we were to return a bound + // variable, we'd be computing a lower-bound, but not + // necessarily the *greatest* lower-bound. + // + // Unfortunately, this problem is non-trivial to solve, + // because we do not know at the time of computing the GLB + // whether a GLB(a,b) exists or not, because we haven't + // run region inference (or indeed, even fully computed + // the region hierarchy!). The current algorithm seems to + // works ok in practice. + + if a_r.is_some() && b_r.is_some() && only_new_vars { + // Related to exactly one bound variable from each fn: + return rev_lookup(infcx, span, a_map, a_r.unwrap()); + } else if a_r.is_none() && b_r.is_none() { + // Not related to bound variables from either fn: + assert!(!r0.is_bound()); + return r0; + } else { + // Other: + return fresh_bound_variable(infcx, debruijn); + } + } + + fn rev_lookup(infcx: &InferCtxt, + span: Span, + a_map: &FnvHashMap, + r: ty::Region) -> ty::Region + { + for (a_br, a_r) in a_map { + if *a_r == r { + return ty::ReLateBound(ty::DebruijnIndex::new(1), *a_br); + } + } + infcx.tcx.sess.span_bug( + span, + &format!("could not find original bound region for {:?}", r)); + } + + fn fresh_bound_variable(infcx: &InferCtxt, debruijn: ty::DebruijnIndex) -> ty::Region { + infcx.region_vars.new_bound(debruijn) + } + } +} + +fn var_ids<'a, 'tcx>(fields: &CombineFields<'a, 'tcx>, + map: &FnvHashMap) + -> Vec { + map.iter() + .map(|(_, r)| match *r { + ty::ReVar(r) => { r } + r => { + fields.tcx().sess.span_bug( + fields.trace.origin.span(), + &format!("found non-region-vid: {:?}", r)); + } + }) + .collect() +} + +fn is_var_in_set(new_vars: &[ty::RegionVid], r: ty::Region) -> bool { + match r { + ty::ReVar(ref v) => new_vars.iter().any(|x| x == v), + _ => false + } +} + +fn fold_regions_in<'tcx, T, F>(tcx: &TyCtxt<'tcx>, + unbound_value: &T, + mut fldr: F) + -> T + where T: TypeFoldable<'tcx>, + F: FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region, +{ + tcx.fold_regions(unbound_value, &mut false, |region, current_depth| { + // we should only be encountering "escaping" late-bound regions here, + // because the ones at the current level should have been replaced + // with fresh variables + assert!(match region { + ty::ReLateBound(..) => false, + _ => true + }); + + fldr(region, ty::DebruijnIndex::new(current_depth)) + }) +} + +impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> { + fn tainted_regions(&self, snapshot: &CombinedSnapshot, r: ty::Region) -> Vec { + self.region_vars.tainted(&snapshot.region_vars_snapshot, r) + } + + fn region_vars_confined_to_snapshot(&self, + snapshot: &CombinedSnapshot) + -> Vec + { + /*! + * Returns the set of region variables that do not affect any + * types/regions which existed before `snapshot` was + * started. This is used in the sub/lub/glb computations. The + * idea here is that when we are computing lub/glb of two + * regions, we sometimes create intermediate region variables. + * Those region variables may touch some of the skolemized or + * other "forbidden" regions we created to replace bound + * regions, but they don't really represent an "external" + * constraint. + * + * However, sometimes fresh variables are created for other + * purposes too, and those *may* represent an external + * constraint. In particular, when a type variable is + * instantiated, we create region variables for all the + * regions that appear within, and if that type variable + * pre-existed the snapshot, then those region variables + * represent external constraints. + * + * An example appears in the unit test + * `sub_free_bound_false_infer`. In this test, we want to + * know whether + * + * ```rust + * fn(_#0t) <: for<'a> fn(&'a int) + * ``` + * + * Note that the subtype has a type variable. Because the type + * variable can't be instantiated with a region that is bound + * in the fn signature, this comparison ought to fail. But if + * we're not careful, it will succeed. + * + * The reason is that when we walk through the subtyping + * algorith, we begin by replacing `'a` with a skolemized + * variable `'1`. We then have `fn(_#0t) <: fn(&'1 int)`. This + * can be made true by unifying `_#0t` with `&'1 int`. In the + * process, we create a fresh variable for the skolemized + * region, `'$2`, and hence we have that `_#0t == &'$2 + * int`. However, because `'$2` was created during the sub + * computation, if we're not careful we will erroneously + * assume it is one of the transient region variables + * representing a lub/glb internally. Not good. + * + * To prevent this, we check for type variables which were + * unified during the snapshot, and say that any region + * variable created during the snapshot but which finds its + * way into a type variable is considered to "escape" the + * snapshot. + */ + + let mut region_vars = + self.region_vars.vars_created_since_snapshot(&snapshot.region_vars_snapshot); + + let escaping_types = + self.type_variables.borrow_mut().types_escaping_snapshot(&snapshot.type_snapshot); + + let mut escaping_region_vars = FnvHashSet(); + for ty in &escaping_types { + self.tcx.collect_regions(ty, &mut escaping_region_vars); + } + + region_vars.retain(|®ion_vid| { + let r = ty::ReVar(region_vid); + !escaping_region_vars.contains(&r) + }); + + debug!("region_vars_confined_to_snapshot: region_vars={:?} escaping_types={:?}", + region_vars, + escaping_types); + + region_vars + } +} + +pub fn skolemize_late_bound_regions<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, + binder: &ty::Binder, + snapshot: &CombinedSnapshot) + -> (T, SkolemizationMap) + where T : TypeFoldable<'tcx> +{ + /*! + * Replace all regions bound by `binder` with skolemized regions and + * return a map indicating which bound-region was replaced with what + * skolemized region. This is the first step of checking subtyping + * when higher-ranked things are involved. See `README.md` for more + * details. + */ + + let (result, map) = infcx.tcx.replace_late_bound_regions(binder, |br| { + infcx.region_vars.new_skolemized(br, &snapshot.region_vars_snapshot) + }); + + debug!("skolemize_bound_regions(binder={:?}, result={:?}, map={:?})", + binder, + result, + map); + + (result, map) +} + +pub fn leak_check<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, + skol_map: &SkolemizationMap, + snapshot: &CombinedSnapshot) + -> Result<(),(ty::BoundRegion,ty::Region)> +{ + /*! + * Searches the region constriants created since `snapshot` was started + * and checks to determine whether any of the skolemized regions created + * in `skol_map` would "escape" -- meaning that they are related to + * other regions in some way. If so, the higher-ranked subtyping doesn't + * hold. See `README.md` for more details. + */ + + debug!("leak_check: skol_map={:?}", + skol_map); + + let new_vars = infcx.region_vars_confined_to_snapshot(snapshot); + for (&skol_br, &skol) in skol_map { + let tainted = infcx.tainted_regions(snapshot, skol); + for &tainted_region in &tainted { + // Each skolemized should only be relatable to itself + // or new variables: + match tainted_region { + ty::ReVar(vid) => { + if new_vars.iter().any(|&x| x == vid) { continue; } + } + _ => { + if tainted_region == skol { continue; } + } + }; + + debug!("{:?} (which replaced {:?}) is tainted by {:?}", + skol, + skol_br, + tainted_region); + + // A is not as polymorphic as B: + return Err((skol_br, tainted_region)); + } + } + Ok(()) +} + +/// This code converts from skolemized regions back to late-bound +/// regions. It works by replacing each region in the taint set of a +/// skolemized region with a bound-region. The bound region will be bound +/// by the outer-most binder in `value`; the caller must ensure that there is +/// such a binder and it is the right place. +/// +/// This routine is only intended to be used when the leak-check has +/// passed; currently, it's used in the trait matching code to create +/// a set of nested obligations frmo an impl that matches against +/// something higher-ranked. More details can be found in +/// `librustc/middle/traits/README.md`. +/// +/// As a brief example, consider the obligation `for<'a> Fn(&'a int) +/// -> &'a int`, and the impl: +/// +/// impl Fn for SomethingOrOther +/// where A : Clone +/// { ... } +/// +/// Here we will have replaced `'a` with a skolemized region +/// `'0`. This means that our substitution will be `{A=>&'0 +/// int, R=>&'0 int}`. +/// +/// When we apply the substitution to the bounds, we will wind up with +/// `&'0 int : Clone` as a predicate. As a last step, we then go and +/// replace `'0` with a late-bound region `'a`. The depth is matched +/// to the depth of the predicate, in this case 1, so that the final +/// predicate is `for<'a> &'a int : Clone`. +pub fn plug_leaks<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, + skol_map: SkolemizationMap, + snapshot: &CombinedSnapshot, + value: &T) + -> T + where T : TypeFoldable<'tcx> +{ + debug_assert!(leak_check(infcx, &skol_map, snapshot).is_ok()); + + debug!("plug_leaks(skol_map={:?}, value={:?})", + skol_map, + value); + + // Compute a mapping from the "taint set" of each skolemized + // region back to the `ty::BoundRegion` that it originally + // represented. Because `leak_check` passed, we know that + // these taint sets are mutually disjoint. + let inv_skol_map: FnvHashMap = + skol_map + .into_iter() + .flat_map(|(skol_br, skol)| { + infcx.tainted_regions(snapshot, skol) + .into_iter() + .map(move |tainted_region| (tainted_region, skol_br)) + }) + .collect(); + + debug!("plug_leaks: inv_skol_map={:?}", + inv_skol_map); + + // Remove any instantiated type variables from `value`; those can hide + // references to regions from the `fold_regions` code below. + let value = infcx.resolve_type_vars_if_possible(value); + + // Map any skolemization byproducts back to a late-bound + // region. Put that late-bound region at whatever the outermost + // binder is that we encountered in `value`. The caller is + // responsible for ensuring that (a) `value` contains at least one + // binder and (b) that binder is the one we want to use. + let result = infcx.tcx.fold_regions(&value, &mut false, |r, current_depth| { + match inv_skol_map.get(&r) { + None => r, + Some(br) => { + // It is the responsibility of the caller to ensure + // that each skolemized region appears within a + // binder. In practice, this routine is only used by + // trait checking, and all of the skolemized regions + // appear inside predicates, which always have + // binders, so this assert is satisfied. + assert!(current_depth > 1); + + ty::ReLateBound(ty::DebruijnIndex::new(current_depth - 1), br.clone()) + } + } + }); + + debug!("plug_leaks: result={:?}", + result); + + result +} diff --git a/src/librustc/infer/lattice.rs b/src/librustc/infer/lattice.rs new file mode 100644 index 00000000000..17ad32e742e --- /dev/null +++ b/src/librustc/infer/lattice.rs @@ -0,0 +1,84 @@ +// Copyright 2012 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! # Lattice Variables +//! +//! This file contains generic code for operating on inference variables +//! that are characterized by an upper- and lower-bound. The logic and +//! reasoning is explained in detail in the large comment in `infer.rs`. +//! +//! The code in here is defined quite generically so that it can be +//! applied both to type variables, which represent types being inferred, +//! and fn variables, which represent function types being inferred. +//! It may eventually be applied to their types as well, who knows. +//! In some cases, the functions are also generic with respect to the +//! operation on the lattice (GLB vs LUB). +//! +//! Although all the functions are generic, we generally write the +//! comments in a way that is specific to type variables and the LUB +//! operation. It's just easier that way. +//! +//! In general all of the functions are defined parametrically +//! over a `LatticeValue`, which is a value defined with respect to +//! a lattice. + +use super::combine; +use super::InferCtxt; + +use ty::TyVar; +use ty::{self, Ty}; +use ty::relate::{RelateResult, TypeRelation}; + +pub trait LatticeDir<'f,'tcx> : TypeRelation<'f,'tcx> { + fn infcx(&self) -> &'f InferCtxt<'f, 'tcx>; + + // Relates the type `v` to `a` and `b` such that `v` represents + // the LUB/GLB of `a` and `b` as appropriate. + fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>; +} + +pub fn super_lattice_tys<'a,'tcx,L:LatticeDir<'a,'tcx>>(this: &mut L, + a: Ty<'tcx>, + b: Ty<'tcx>) + -> RelateResult<'tcx, Ty<'tcx>> + where 'tcx: 'a +{ + debug!("{}.lattice_tys({:?}, {:?})", + this.tag(), + a, + b); + + if a == b { + return Ok(a); + } + + let infcx = this.infcx(); + let a = infcx.type_variables.borrow_mut().replace_if_possible(a); + let b = infcx.type_variables.borrow_mut().replace_if_possible(b); + match (&a.sty, &b.sty) { + (&ty::TyInfer(TyVar(..)), &ty::TyInfer(TyVar(..))) + if infcx.type_var_diverges(a) && infcx.type_var_diverges(b) => { + let v = infcx.next_diverging_ty_var(); + this.relate_bound(v, a, b)?; + Ok(v) + } + + (&ty::TyInfer(TyVar(..)), _) | + (_, &ty::TyInfer(TyVar(..))) => { + let v = infcx.next_ty_var(); + this.relate_bound(v, a, b)?; + Ok(v) + } + + _ => { + combine::super_combine_tys(this.infcx(), this, a, b) + } + } +} diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs new file mode 100644 index 00000000000..00b85929b4b --- /dev/null +++ b/src/librustc/infer/lub.rs @@ -0,0 +1,85 @@ +// Copyright 2012 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::combine::CombineFields; +use super::higher_ranked::HigherRankedRelations; +use super::InferCtxt; +use super::lattice::{self, LatticeDir}; +use super::Subtype; + +use ty::{self, Ty, TyCtxt}; +use ty::relate::{Relate, RelateResult, TypeRelation}; + +/// "Least upper bound" (common supertype) +pub struct Lub<'a, 'tcx: 'a> { + fields: CombineFields<'a, 'tcx> +} + +impl<'a, 'tcx> Lub<'a, 'tcx> { + pub fn new(fields: CombineFields<'a, 'tcx>) -> Lub<'a, 'tcx> { + Lub { fields: fields } + } +} + +impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Lub<'a, 'tcx> { + fn tag(&self) -> &'static str { "Lub" } + + fn tcx(&self) -> &'a TyCtxt<'tcx> { self.fields.tcx() } + + fn a_is_expected(&self) -> bool { self.fields.a_is_expected } + + fn relate_with_variance>(&mut self, + variance: ty::Variance, + a: &T, + b: &T) + -> RelateResult<'tcx, T> + { + match variance { + ty::Invariant => self.fields.equate().relate(a, b), + ty::Covariant => self.relate(a, b), + ty::Bivariant => self.fields.bivariate().relate(a, b), + ty::Contravariant => self.fields.glb().relate(a, b), + } + } + + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + lattice::super_lattice_tys(self, a, b) + } + + fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> { + debug!("{}.regions({:?}, {:?})", + self.tag(), + a, + b); + + let origin = Subtype(self.fields.trace.clone()); + Ok(self.fields.infcx.region_vars.lub_regions(origin, a, b)) + } + + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where T: Relate<'a, 'tcx> + { + self.fields.higher_ranked_lub(a, b) + } +} + +impl<'a, 'tcx> LatticeDir<'a,'tcx> for Lub<'a, 'tcx> { + fn infcx(&self) -> &'a InferCtxt<'a,'tcx> { + self.fields.infcx + } + + fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { + let mut sub = self.fields.sub(); + sub.relate(&a, &v)?; + sub.relate(&b, &v)?; + Ok(()) + } +} diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs new file mode 100644 index 00000000000..bc4c9fd2ccf --- /dev/null +++ b/src/librustc/infer/mod.rs @@ -0,0 +1,1672 @@ +// Copyright 2012-2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! See the Book for more information. + +pub use self::LateBoundRegionConversionTime::*; +pub use self::RegionVariableOrigin::*; +pub use self::SubregionOrigin::*; +pub use self::ValuePairs::*; +pub use ty::IntVarValue; +pub use self::freshen::TypeFreshener; +pub use self::region_inference::{GenericKind, VerifyBound}; + +use middle::def_id::DefId; +use rustc_front::hir; +use middle::free_region::FreeRegionMap; +use middle::mem_categorization as mc; +use middle::mem_categorization::McResult; +use middle::region::CodeExtent; +use ty::subst; +use ty::subst::Substs; +use ty::subst::Subst; +use traits::{self, ProjectionMode}; +use ty::adjustment; +use ty::{TyVid, IntVid, FloatVid}; +use ty::{self, Ty, TyCtxt}; +use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; +use ty::fold::{TypeFolder, TypeFoldable}; +use ty::relate::{Relate, RelateResult, TypeRelation}; +use rustc_data_structures::unify::{self, UnificationTable}; +use std::cell::{RefCell, Ref}; +use std::fmt; +use syntax::ast; +use syntax::codemap; +use syntax::codemap::{Span, DUMMY_SP}; +use syntax::errors::DiagnosticBuilder; +use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap}; + +use self::combine::CombineFields; +use self::region_inference::{RegionVarBindings, RegionSnapshot}; +use self::error_reporting::ErrorReporting; +use self::unify_key::ToType; + +pub mod bivariate; +pub mod combine; +pub mod equate; +pub mod error_reporting; +pub mod glb; +mod higher_ranked; +pub mod lattice; +pub mod lub; +pub mod region_inference; +pub mod resolve; +mod freshen; +pub mod sub; +pub mod type_variable; +pub mod unify_key; + +pub type Bound = Option; +pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result" +pub type FixupResult = Result; // "fixup result" + +pub struct InferCtxt<'a, 'tcx: 'a> { + pub tcx: &'a TyCtxt<'tcx>, + + pub tables: &'a RefCell>, + + // We instantiate UnificationTable with bounds because the + // types that might instantiate a general type variable have an + // order, represented by its upper and lower bounds. + type_variables: RefCell>, + + // Map from integral variable to the kind of integer it represents + int_unification_table: RefCell>, + + // Map from floating variable to the kind of float it represents + float_unification_table: RefCell>, + + // For region variables. + region_vars: RegionVarBindings<'a, 'tcx>, + + pub parameter_environment: ty::ParameterEnvironment<'a, 'tcx>, + + // the set of predicates on which errors have been reported, to + // avoid reporting the same error twice. + pub reported_trait_errors: RefCell>>, + + // This is a temporary field used for toggling on normalization in the inference context, + // as we move towards the approach described here: + // https://internals.rust-lang.org/t/flattening-the-contexts-for-fun-and-profit/2293 + // At a point sometime in the future normalization will be done by the typing context + // directly. + normalize: bool, + + // Sadly, the behavior of projection varies a bit depending on the + // stage of compilation. The specifics are given in the + // documentation for `ProjectionMode`. + projection_mode: ProjectionMode, + + err_count_on_creation: usize, +} + +/// A map returned by `skolemize_late_bound_regions()` indicating the skolemized +/// region that each late-bound region was replaced with. +pub type SkolemizationMap = FnvHashMap; + +/// Why did we require that the two types be related? +/// +/// See `error_reporting.rs` for more details +#[derive(Clone, Copy, Debug)] +pub enum TypeOrigin { + // Not yet categorized in a better way + Misc(Span), + + // Checking that method of impl is compatible with trait + MethodCompatCheck(Span), + + // Checking that this expression can be assigned where it needs to be + // FIXME(eddyb) #11161 is the original Expr required? + ExprAssignable(Span), + + // Relating trait refs when resolving vtables + RelateTraitRefs(Span), + + // Relating self types when resolving vtables + RelateSelfType(Span), + + // Relating trait type parameters to those found in impl etc + RelateOutputImplTypes(Span), + + // Computing common supertype in the arms of a match expression + MatchExpressionArm(Span, Span, hir::MatchSource), + + // Computing common supertype in an if expression + IfExpression(Span), + + // Computing common supertype of an if expression with no else counter-part + IfExpressionWithNoElse(Span), + + // Computing common supertype in a range expression + RangeExpression(Span), + + // `where a == b` + EquatePredicate(Span), +} + +impl TypeOrigin { + fn as_str(&self) -> &'static str { + match self { + &TypeOrigin::Misc(_) | + &TypeOrigin::RelateSelfType(_) | + &TypeOrigin::RelateOutputImplTypes(_) | + &TypeOrigin::ExprAssignable(_) => "mismatched types", + &TypeOrigin::RelateTraitRefs(_) => "mismatched traits", + &TypeOrigin::MethodCompatCheck(_) => "method not compatible with trait", + &TypeOrigin::MatchExpressionArm(_, _, source) => match source { + hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types", + _ => "match arms have incompatible types", + }, + &TypeOrigin::IfExpression(_) => "if and else have incompatible types", + &TypeOrigin::IfExpressionWithNoElse(_) => "if may be missing an else clause", + &TypeOrigin::RangeExpression(_) => "start and end of range have incompatible types", + &TypeOrigin::EquatePredicate(_) => "equality predicate not satisfied", + } + } +} + +impl fmt::Display for TypeOrigin { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(),fmt::Error> { + fmt::Display::fmt(self.as_str(), f) + } +} + +/// See `error_reporting.rs` for more details +#[derive(Clone, Debug)] +pub enum ValuePairs<'tcx> { + Types(ExpectedFound>), + TraitRefs(ExpectedFound>), + PolyTraitRefs(ExpectedFound>), +} + +/// The trace designates the path through inference that we took to +/// encounter an error or subtyping constraint. +/// +/// See `error_reporting.rs` for more details. +#[derive(Clone)] +pub struct TypeTrace<'tcx> { + origin: TypeOrigin, + values: ValuePairs<'tcx>, +} + +/// The origin of a `r1 <= r2` constraint. +/// +/// See `error_reporting.rs` for more details +#[derive(Clone, Debug)] +pub enum SubregionOrigin<'tcx> { + // Arose from a subtyping relation + Subtype(TypeTrace<'tcx>), + + // Stack-allocated closures cannot outlive innermost loop + // or function so as to ensure we only require finite stack + InfStackClosure(Span), + + // Invocation of closure must be within its lifetime + InvokeClosure(Span), + + // Dereference of reference must be within its lifetime + DerefPointer(Span), + + // Closure bound must not outlive captured free variables + FreeVariable(Span, ast::NodeId), + + // Index into slice must be within its lifetime + IndexSlice(Span), + + // When casting `&'a T` to an `&'b Trait` object, + // relating `'a` to `'b` + RelateObjectBound(Span), + + // Some type parameter was instantiated with the given type, + // and that type must outlive some region. + RelateParamBound(Span, Ty<'tcx>), + + // The given region parameter was instantiated with a region + // that must outlive some other region. + RelateRegionParamBound(Span), + + // A bound placed on type parameters that states that must outlive + // the moment of their instantiation. + RelateDefaultParamBound(Span, Ty<'tcx>), + + // Creating a pointer `b` to contents of another reference + Reborrow(Span), + + // Creating a pointer `b` to contents of an upvar + ReborrowUpvar(Span, ty::UpvarId), + + // Data with type `Ty<'tcx>` was borrowed + DataBorrowed(Ty<'tcx>, Span), + + // (&'a &'b T) where a >= b + ReferenceOutlivesReferent(Ty<'tcx>, Span), + + // Type or region parameters must be in scope. + ParameterInScope(ParameterOrigin, Span), + + // The type T of an expression E must outlive the lifetime for E. + ExprTypeIsNotInScope(Ty<'tcx>, Span), + + // A `ref b` whose region does not enclose the decl site + BindingTypeIsNotValidAtDecl(Span), + + // Regions appearing in a method receiver must outlive method call + CallRcvr(Span), + + // Regions appearing in a function argument must outlive func call + CallArg(Span), + + // Region in return type of invoked fn must enclose call + CallReturn(Span), + + // Operands must be in scope + Operand(Span), + + // Region resulting from a `&` expr must enclose the `&` expr + AddrOf(Span), + + // An auto-borrow that does not enclose the expr where it occurs + AutoBorrow(Span), + + // Region constraint arriving from destructor safety + SafeDestructor(Span), +} + +/// Places that type/region parameters can appear. +#[derive(Clone, Copy, Debug)] +pub enum ParameterOrigin { + Path, // foo::bar + MethodCall, // foo.bar() <-- parameters on impl providing bar() + OverloadedOperator, // a + b when overloaded + OverloadedDeref, // *a when overloaded +} + +/// Times when we replace late-bound regions with variables: +#[derive(Clone, Copy, Debug)] +pub enum LateBoundRegionConversionTime { + /// when a fn is called + FnCall, + + /// when two higher-ranked types are compared + HigherRankedType, + + /// when projecting an associated type + AssocTypeProjection(ast::Name), +} + +/// Reasons to create a region inference variable +/// +/// See `error_reporting.rs` for more details +#[derive(Clone, Debug)] +pub enum RegionVariableOrigin { + // Region variables created for ill-categorized reasons, + // mostly indicates places in need of refactoring + MiscVariable(Span), + + // Regions created by a `&P` or `[...]` pattern + PatternRegion(Span), + + // Regions created by `&` operator + AddrOfRegion(Span), + + // Regions created as part of an autoref of a method receiver + Autoref(Span), + + // Regions created as part of an automatic coercion + Coercion(Span), + + // Region variables created as the values for early-bound regions + EarlyBoundRegion(Span, ast::Name), + + // Region variables created for bound regions + // in a function or method that is called + LateBoundRegion(Span, ty::BoundRegion, LateBoundRegionConversionTime), + + UpvarRegion(ty::UpvarId, Span), + + BoundRegionInCoherence(ast::Name), +} + +#[derive(Copy, Clone, Debug)] +pub enum FixupError { + UnresolvedIntTy(IntVid), + UnresolvedFloatTy(FloatVid), + UnresolvedTy(TyVid) +} + +pub fn fixup_err_to_string(f: FixupError) -> String { + use self::FixupError::*; + + match f { + UnresolvedIntTy(_) => { + "cannot determine the type of this integer; add a suffix to \ + specify the type explicitly".to_string() + } + UnresolvedFloatTy(_) => { + "cannot determine the type of this number; add a suffix to specify \ + the type explicitly".to_string() + } + UnresolvedTy(_) => "unconstrained type".to_string(), + } +} + +pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a TyCtxt<'tcx>, + tables: &'a RefCell>, + param_env: Option>, + projection_mode: ProjectionMode) + -> InferCtxt<'a, 'tcx> { + InferCtxt { + tcx: tcx, + tables: tables, + type_variables: RefCell::new(type_variable::TypeVariableTable::new()), + int_unification_table: RefCell::new(UnificationTable::new()), + float_unification_table: RefCell::new(UnificationTable::new()), + region_vars: RegionVarBindings::new(tcx), + parameter_environment: param_env.unwrap_or(tcx.empty_parameter_environment()), + reported_trait_errors: RefCell::new(FnvHashSet()), + normalize: false, + projection_mode: projection_mode, + err_count_on_creation: tcx.sess.err_count() + } +} + +pub fn normalizing_infer_ctxt<'a, 'tcx>(tcx: &'a TyCtxt<'tcx>, + tables: &'a RefCell>, + projection_mode: ProjectionMode) + -> InferCtxt<'a, 'tcx> { + let mut infcx = new_infer_ctxt(tcx, tables, None, projection_mode); + infcx.normalize = true; + infcx +} + +/// Computes the least upper-bound of `a` and `b`. If this is not possible, reports an error and +/// returns ty::err. +pub fn common_supertype<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, + origin: TypeOrigin, + a_is_expected: bool, + a: Ty<'tcx>, + b: Ty<'tcx>) + -> Ty<'tcx> +{ + debug!("common_supertype({:?}, {:?})", + a, b); + + let trace = TypeTrace { + origin: origin, + values: Types(expected_found(a_is_expected, a, b)) + }; + + let result = cx.commit_if_ok(|_| cx.lub(a_is_expected, trace.clone()).relate(&a, &b)); + match result { + Ok(t) => t, + Err(ref err) => { + cx.report_and_explain_type_error(trace, err).emit(); + cx.tcx.types.err + } + } +} + +pub fn mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, + a_is_expected: bool, + origin: TypeOrigin, + a: Ty<'tcx>, + b: Ty<'tcx>) + -> UnitResult<'tcx> +{ + debug!("mk_subty({:?} <: {:?})", a, b); + cx.sub_types(a_is_expected, origin, a, b) +} + +pub fn can_mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, + a: Ty<'tcx>, + b: Ty<'tcx>) + -> UnitResult<'tcx> { + debug!("can_mk_subty({:?} <: {:?})", a, b); + cx.probe(|_| { + let trace = TypeTrace { + origin: TypeOrigin::Misc(codemap::DUMMY_SP), + values: Types(expected_found(true, a, b)) + }; + cx.sub(true, trace).relate(&a, &b).map(|_| ()) + }) +} + +pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) + -> UnitResult<'tcx> +{ + cx.can_equate(&a, &b) +} + +pub fn mk_subr<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, + origin: SubregionOrigin<'tcx>, + a: ty::Region, + b: ty::Region) { + debug!("mk_subr({:?} <: {:?})", a, b); + let snapshot = cx.region_vars.start_snapshot(); + cx.region_vars.make_subregion(origin, a, b); + cx.region_vars.commit(snapshot); +} + +pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, + a_is_expected: bool, + origin: TypeOrigin, + a: Ty<'tcx>, + b: Ty<'tcx>) + -> UnitResult<'tcx> +{ + debug!("mk_eqty({:?} <: {:?})", a, b); + cx.eq_types(a_is_expected, origin, a, b) +} + +pub fn mk_eq_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, + a_is_expected: bool, + origin: TypeOrigin, + a: ty::TraitRef<'tcx>, + b: ty::TraitRef<'tcx>) + -> UnitResult<'tcx> +{ + debug!("mk_eq_trait_refs({:?} = {:?})", a, b); + cx.eq_trait_refs(a_is_expected, origin, a, b) +} + +pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, + a_is_expected: bool, + origin: TypeOrigin, + a: ty::PolyTraitRef<'tcx>, + b: ty::PolyTraitRef<'tcx>) + -> UnitResult<'tcx> +{ + debug!("mk_sub_poly_trait_refs({:?} <: {:?})", a, b); + cx.sub_poly_trait_refs(a_is_expected, origin, a, b) +} + +pub fn mk_eq_impl_headers<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, + a_is_expected: bool, + origin: TypeOrigin, + a: &ty::ImplHeader<'tcx>, + b: &ty::ImplHeader<'tcx>) + -> UnitResult<'tcx> +{ + debug!("mk_eq_impl_header({:?} = {:?})", a, b); + match (a.trait_ref, b.trait_ref) { + (Some(a_ref), Some(b_ref)) => mk_eq_trait_refs(cx, a_is_expected, origin, a_ref, b_ref), + (None, None) => mk_eqty(cx, a_is_expected, origin, a.self_ty, b.self_ty), + _ => cx.tcx.sess.bug("mk_eq_impl_headers given mismatched impl kinds"), + } +} + +fn expected_found(a_is_expected: bool, + a: T, + b: T) + -> ExpectedFound +{ + if a_is_expected { + ExpectedFound {expected: a, found: b} + } else { + ExpectedFound {expected: b, found: a} + } +} + +#[must_use = "once you start a snapshot, you should always consume it"] +pub struct CombinedSnapshot { + type_snapshot: type_variable::Snapshot, + int_snapshot: unify::Snapshot, + float_snapshot: unify::Snapshot, + region_vars_snapshot: RegionSnapshot, +} + +// NOTE: Callable from trans only! +pub fn normalize_associated_type<'tcx,T>(tcx: &TyCtxt<'tcx>, value: &T) -> T + where T : TypeFoldable<'tcx> +{ + debug!("normalize_associated_type(t={:?})", value); + + let value = tcx.erase_regions(value); + + if !value.has_projection_types() { + return value; + } + + let infcx = new_infer_ctxt(tcx, &tcx.tables, None, ProjectionMode::Any); + let mut selcx = traits::SelectionContext::new(&infcx); + let cause = traits::ObligationCause::dummy(); + let traits::Normalized { value: result, obligations } = + traits::normalize(&mut selcx, cause, &value); + + debug!("normalize_associated_type: result={:?} obligations={:?}", + result, + obligations); + + let mut fulfill_cx = traits::FulfillmentContext::new(); + + for obligation in obligations { + fulfill_cx.register_predicate_obligation(&infcx, obligation); + } + + drain_fulfillment_cx_or_panic(DUMMY_SP, &infcx, &mut fulfill_cx, &result) +} + +pub fn drain_fulfillment_cx_or_panic<'a,'tcx,T>(span: Span, + infcx: &InferCtxt<'a,'tcx>, + fulfill_cx: &mut traits::FulfillmentContext<'tcx>, + result: &T) + -> T + where T : TypeFoldable<'tcx> +{ + match drain_fulfillment_cx(infcx, fulfill_cx, result) { + Ok(v) => v, + Err(errors) => { + infcx.tcx.sess.span_bug( + span, + &format!("Encountered errors `{:?}` fulfilling during trans", + errors)); + } + } +} + +/// Finishes processes any obligations that remain in the fulfillment +/// context, and then "freshens" and returns `result`. This is +/// primarily used during normalization and other cases where +/// processing the obligations in `fulfill_cx` may cause type +/// inference variables that appear in `result` to be unified, and +/// hence we need to process those obligations to get the complete +/// picture of the type. +pub fn drain_fulfillment_cx<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, + fulfill_cx: &mut traits::FulfillmentContext<'tcx>, + result: &T) + -> Result>> + where T : TypeFoldable<'tcx> +{ + debug!("drain_fulfillment_cx(result={:?})", + result); + + // In principle, we only need to do this so long as `result` + // contains unbound type parameters. It could be a slight + // optimization to stop iterating early. + match fulfill_cx.select_all_or_error(infcx) { + Ok(()) => { } + Err(errors) => { + return Err(errors); + } + } + + let result = infcx.resolve_type_vars_if_possible(result); + Ok(infcx.tcx.erase_regions(&result)) +} + +impl<'a, 'tcx> InferCtxt<'a, 'tcx> { + pub fn projection_mode(&self) -> ProjectionMode { + self.projection_mode + } + + pub fn freshen>(&self, t: T) -> T { + t.fold_with(&mut self.freshener()) + } + + pub fn type_var_diverges(&'a self, ty: Ty) -> bool { + match ty.sty { + ty::TyInfer(ty::TyVar(vid)) => self.type_variables.borrow().var_diverges(vid), + _ => false + } + } + + pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx> { + freshen::TypeFreshener::new(self) + } + + pub fn type_is_unconstrained_numeric(&'a self, ty: Ty) -> UnconstrainedNumeric { + use ty::error::UnconstrainedNumeric::Neither; + use ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; + match ty.sty { + ty::TyInfer(ty::IntVar(vid)) => { + if self.int_unification_table.borrow_mut().has_value(vid) { + Neither + } else { + UnconstrainedInt + } + }, + ty::TyInfer(ty::FloatVar(vid)) => { + if self.float_unification_table.borrow_mut().has_value(vid) { + Neither + } else { + UnconstrainedFloat + } + }, + _ => Neither, + } + } + + /// Returns a type variable's default fallback if any exists. A default + /// must be attached to the variable when created, if it is created + /// without a default, this will return None. + /// + /// This code does not apply to integral or floating point variables, + /// only to use declared defaults. + /// + /// See `new_ty_var_with_default` to create a type variable with a default. + /// See `type_variable::Default` for details about what a default entails. + pub fn default(&self, ty: Ty<'tcx>) -> Option> { + match ty.sty { + ty::TyInfer(ty::TyVar(vid)) => self.type_variables.borrow().default(vid), + _ => None + } + } + + pub fn unsolved_variables(&self) -> Vec> { + let mut variables = Vec::new(); + + let unbound_ty_vars = self.type_variables + .borrow_mut() + .unsolved_variables() + .into_iter() + .map(|t| self.tcx.mk_var(t)); + + let unbound_int_vars = self.int_unification_table + .borrow_mut() + .unsolved_variables() + .into_iter() + .map(|v| self.tcx.mk_int_var(v)); + + let unbound_float_vars = self.float_unification_table + .borrow_mut() + .unsolved_variables() + .into_iter() + .map(|v| self.tcx.mk_float_var(v)); + + variables.extend(unbound_ty_vars); + variables.extend(unbound_int_vars); + variables.extend(unbound_float_vars); + + return variables; + } + + fn combine_fields(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>) + -> CombineFields<'a, 'tcx> { + CombineFields {infcx: self, + a_is_expected: a_is_expected, + trace: trace, + cause: None} + } + + // public so that it can be used from the rustc_driver unit tests + pub fn equate(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>) + -> equate::Equate<'a, 'tcx> + { + self.combine_fields(a_is_expected, trace).equate() + } + + // public so that it can be used from the rustc_driver unit tests + pub fn sub(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>) + -> sub::Sub<'a, 'tcx> + { + self.combine_fields(a_is_expected, trace).sub() + } + + // public so that it can be used from the rustc_driver unit tests + pub fn lub(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>) + -> lub::Lub<'a, 'tcx> + { + self.combine_fields(a_is_expected, trace).lub() + } + + // public so that it can be used from the rustc_driver unit tests + pub fn glb(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>) + -> glb::Glb<'a, 'tcx> + { + self.combine_fields(a_is_expected, trace).glb() + } + + fn start_snapshot(&self) -> CombinedSnapshot { + CombinedSnapshot { + type_snapshot: self.type_variables.borrow_mut().snapshot(), + int_snapshot: self.int_unification_table.borrow_mut().snapshot(), + float_snapshot: self.float_unification_table.borrow_mut().snapshot(), + region_vars_snapshot: self.region_vars.start_snapshot(), + } + } + + fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot) { + debug!("rollback_to(cause={})", cause); + let CombinedSnapshot { type_snapshot, + int_snapshot, + float_snapshot, + region_vars_snapshot } = snapshot; + + self.type_variables + .borrow_mut() + .rollback_to(type_snapshot); + self.int_unification_table + .borrow_mut() + .rollback_to(int_snapshot); + self.float_unification_table + .borrow_mut() + .rollback_to(float_snapshot); + self.region_vars + .rollback_to(region_vars_snapshot); + } + + fn commit_from(&self, snapshot: CombinedSnapshot) { + debug!("commit_from!"); + let CombinedSnapshot { type_snapshot, + int_snapshot, + float_snapshot, + region_vars_snapshot } = snapshot; + + self.type_variables + .borrow_mut() + .commit(type_snapshot); + self.int_unification_table + .borrow_mut() + .commit(int_snapshot); + self.float_unification_table + .borrow_mut() + .commit(float_snapshot); + self.region_vars + .commit(region_vars_snapshot); + } + + /// Execute `f` and commit the bindings + pub fn commit_unconditionally(&self, f: F) -> R where + F: FnOnce() -> R, + { + debug!("commit()"); + let snapshot = self.start_snapshot(); + let r = f(); + self.commit_from(snapshot); + r + } + + /// Execute `f` and commit the bindings if closure `f` returns `Ok(_)` + pub fn commit_if_ok(&self, f: F) -> Result where + F: FnOnce(&CombinedSnapshot) -> Result + { + debug!("commit_if_ok()"); + let snapshot = self.start_snapshot(); + let r = f(&snapshot); + debug!("commit_if_ok() -- r.is_ok() = {}", r.is_ok()); + match r { + Ok(_) => { self.commit_from(snapshot); } + Err(_) => { self.rollback_to("commit_if_ok -- error", snapshot); } + } + r + } + + /// Execute `f` and commit only the region bindings if successful. + /// The function f must be very careful not to leak any non-region + /// variables that get created. + pub fn commit_regions_if_ok(&self, f: F) -> Result where + F: FnOnce() -> Result + { + debug!("commit_regions_if_ok()"); + let CombinedSnapshot { type_snapshot, + int_snapshot, + float_snapshot, + region_vars_snapshot } = self.start_snapshot(); + + let r = self.commit_if_ok(|_| f()); + + debug!("commit_regions_if_ok: rolling back everything but regions"); + + // Roll back any non-region bindings - they should be resolved + // inside `f`, with, e.g. `resolve_type_vars_if_possible`. + self.type_variables + .borrow_mut() + .rollback_to(type_snapshot); + self.int_unification_table + .borrow_mut() + .rollback_to(int_snapshot); + self.float_unification_table + .borrow_mut() + .rollback_to(float_snapshot); + + // Commit region vars that may escape through resolved types. + self.region_vars + .commit(region_vars_snapshot); + + r + } + + /// Execute `f` then unroll any bindings it creates + pub fn probe(&self, f: F) -> R where + F: FnOnce(&CombinedSnapshot) -> R, + { + debug!("probe()"); + let snapshot = self.start_snapshot(); + let r = f(&snapshot); + self.rollback_to("probe", snapshot); + r + } + + pub fn add_given(&self, + sub: ty::FreeRegion, + sup: ty::RegionVid) + { + self.region_vars.add_given(sub, sup); + } + + pub fn sub_types(&self, + a_is_expected: bool, + origin: TypeOrigin, + a: Ty<'tcx>, + b: Ty<'tcx>) + -> UnitResult<'tcx> + { + debug!("sub_types({:?} <: {:?})", a, b); + self.commit_if_ok(|_| { + let trace = TypeTrace::types(origin, a_is_expected, a, b); + self.sub(a_is_expected, trace).relate(&a, &b).map(|_| ()) + }) + } + + pub fn eq_types(&self, + a_is_expected: bool, + origin: TypeOrigin, + a: Ty<'tcx>, + b: Ty<'tcx>) + -> UnitResult<'tcx> + { + self.commit_if_ok(|_| { + let trace = TypeTrace::types(origin, a_is_expected, a, b); + self.equate(a_is_expected, trace).relate(&a, &b).map(|_| ()) + }) + } + + pub fn eq_trait_refs(&self, + a_is_expected: bool, + origin: TypeOrigin, + a: ty::TraitRef<'tcx>, + b: ty::TraitRef<'tcx>) + -> UnitResult<'tcx> + { + debug!("eq_trait_refs({:?} <: {:?})", + a, + b); + self.commit_if_ok(|_| { + let trace = TypeTrace { + origin: origin, + values: TraitRefs(expected_found(a_is_expected, a.clone(), b.clone())) + }; + self.equate(a_is_expected, trace).relate(&a, &b).map(|_| ()) + }) + } + + pub fn sub_poly_trait_refs(&self, + a_is_expected: bool, + origin: TypeOrigin, + a: ty::PolyTraitRef<'tcx>, + b: ty::PolyTraitRef<'tcx>) + -> UnitResult<'tcx> + { + debug!("sub_poly_trait_refs({:?} <: {:?})", + a, + b); + self.commit_if_ok(|_| { + let trace = TypeTrace { + origin: origin, + values: PolyTraitRefs(expected_found(a_is_expected, a.clone(), b.clone())) + }; + self.sub(a_is_expected, trace).relate(&a, &b).map(|_| ()) + }) + } + + pub fn skolemize_late_bound_regions(&self, + value: &ty::Binder, + snapshot: &CombinedSnapshot) + -> (T, SkolemizationMap) + where T : TypeFoldable<'tcx> + { + /*! See `higher_ranked::skolemize_late_bound_regions` */ + + higher_ranked::skolemize_late_bound_regions(self, value, snapshot) + } + + pub fn leak_check(&self, + skol_map: &SkolemizationMap, + snapshot: &CombinedSnapshot) + -> UnitResult<'tcx> + { + /*! See `higher_ranked::leak_check` */ + + match higher_ranked::leak_check(self, skol_map, snapshot) { + Ok(()) => Ok(()), + Err((br, r)) => Err(TypeError::RegionsInsufficientlyPolymorphic(br, r)) + } + } + + pub fn plug_leaks(&self, + skol_map: SkolemizationMap, + snapshot: &CombinedSnapshot, + value: &T) + -> T + where T : TypeFoldable<'tcx> + { + /*! See `higher_ranked::plug_leaks` */ + + higher_ranked::plug_leaks(self, skol_map, snapshot, value) + } + + pub fn equality_predicate(&self, + span: Span, + predicate: &ty::PolyEquatePredicate<'tcx>) + -> UnitResult<'tcx> { + self.commit_if_ok(|snapshot| { + let (ty::EquatePredicate(a, b), skol_map) = + self.skolemize_late_bound_regions(predicate, snapshot); + let origin = TypeOrigin::EquatePredicate(span); + let () = mk_eqty(self, false, origin, a, b)?; + self.leak_check(&skol_map, snapshot) + }) + } + + pub fn region_outlives_predicate(&self, + span: Span, + predicate: &ty::PolyRegionOutlivesPredicate) + -> UnitResult<'tcx> { + self.commit_if_ok(|snapshot| { + let (ty::OutlivesPredicate(r_a, r_b), skol_map) = + self.skolemize_late_bound_regions(predicate, snapshot); + let origin = RelateRegionParamBound(span); + let () = mk_subr(self, origin, r_b, r_a); // `b : a` ==> `a <= b` + self.leak_check(&skol_map, snapshot) + }) + } + + pub fn next_ty_var_id(&self, diverging: bool) -> TyVid { + self.type_variables + .borrow_mut() + .new_var(diverging, None) + } + + pub fn next_ty_var(&self) -> Ty<'tcx> { + self.tcx.mk_var(self.next_ty_var_id(false)) + } + + pub fn next_ty_var_with_default(&self, + default: Option>) -> Ty<'tcx> { + let ty_var_id = self.type_variables + .borrow_mut() + .new_var(false, default); + + self.tcx.mk_var(ty_var_id) + } + + pub fn next_diverging_ty_var(&self) -> Ty<'tcx> { + self.tcx.mk_var(self.next_ty_var_id(true)) + } + + pub fn next_ty_vars(&self, n: usize) -> Vec> { + (0..n).map(|_i| self.next_ty_var()).collect() + } + + pub fn next_int_var_id(&self) -> IntVid { + self.int_unification_table + .borrow_mut() + .new_key(None) + } + + pub fn next_float_var_id(&self) -> FloatVid { + self.float_unification_table + .borrow_mut() + .new_key(None) + } + + pub fn next_region_var(&self, origin: RegionVariableOrigin) -> ty::Region { + ty::ReVar(self.region_vars.new_region_var(origin)) + } + + pub fn region_vars_for_defs(&self, + span: Span, + defs: &[ty::RegionParameterDef]) + -> Vec { + defs.iter() + .map(|d| self.next_region_var(EarlyBoundRegion(span, d.name))) + .collect() + } + + // We have to take `&mut Substs` in order to provide the correct substitutions for defaults + // along the way, for this reason we don't return them. + pub fn type_vars_for_defs(&self, + span: Span, + space: subst::ParamSpace, + substs: &mut Substs<'tcx>, + defs: &[ty::TypeParameterDef<'tcx>]) { + + for def in defs.iter() { + let default = def.default.map(|default| { + type_variable::Default { + ty: default.subst_spanned(self.tcx, substs, Some(span)), + origin_span: span, + def_id: def.default_def_id + } + }); + + let ty_var = self.next_ty_var_with_default(default); + substs.types.push(space, ty_var); + } + } + + /// Given a set of generics defined on a type or impl, returns a substitution mapping each + /// type/region parameter to a fresh inference variable. + pub fn fresh_substs_for_generics(&self, + span: Span, + generics: &ty::Generics<'tcx>) + -> subst::Substs<'tcx> + { + let type_params = subst::VecPerParamSpace::empty(); + + let region_params = + generics.regions.map( + |d| self.next_region_var(EarlyBoundRegion(span, d.name))); + + let mut substs = subst::Substs::new(type_params, region_params); + + for space in subst::ParamSpace::all().iter() { + self.type_vars_for_defs( + span, + *space, + &mut substs, + generics.types.get_slice(*space)); + } + + return substs; + } + + /// Given a set of generics defined on a trait, returns a substitution mapping each output + /// type/region parameter to a fresh inference variable, and mapping the self type to + /// `self_ty`. + pub fn fresh_substs_for_trait(&self, + span: Span, + generics: &ty::Generics<'tcx>, + self_ty: Ty<'tcx>) + -> subst::Substs<'tcx> + { + + assert!(generics.types.len(subst::SelfSpace) == 1); + assert!(generics.types.len(subst::FnSpace) == 0); + assert!(generics.regions.len(subst::SelfSpace) == 0); + assert!(generics.regions.len(subst::FnSpace) == 0); + + let type_params = Vec::new(); + + let region_param_defs = generics.regions.get_slice(subst::TypeSpace); + let regions = self.region_vars_for_defs(span, region_param_defs); + + let mut substs = subst::Substs::new_trait(type_params, regions, self_ty); + + let type_parameter_defs = generics.types.get_slice(subst::TypeSpace); + self.type_vars_for_defs(span, subst::TypeSpace, &mut substs, type_parameter_defs); + + return substs; + } + + pub fn fresh_bound_region(&self, debruijn: ty::DebruijnIndex) -> ty::Region { + self.region_vars.new_bound(debruijn) + } + + /// Apply `adjustment` to the type of `expr` + pub fn adjust_expr_ty(&self, + expr: &hir::Expr, + adjustment: Option<&adjustment::AutoAdjustment<'tcx>>) + -> Ty<'tcx> + { + let raw_ty = self.expr_ty(expr); + let raw_ty = self.shallow_resolve(raw_ty); + let resolve_ty = |ty: Ty<'tcx>| self.resolve_type_vars_if_possible(&ty); + raw_ty.adjust(self.tcx, + expr.span, + expr.id, + adjustment, + |method_call| self.tables + .borrow() + .method_map + .get(&method_call) + .map(|method| resolve_ty(method.ty))) + } + + pub fn errors_since_creation(&self) -> bool { + self.tcx.sess.err_count() - self.err_count_on_creation != 0 + } + + pub fn node_type(&self, id: ast::NodeId) -> Ty<'tcx> { + match self.tables.borrow().node_types.get(&id) { + Some(&t) => t, + // FIXME + None if self.errors_since_creation() => + self.tcx.types.err, + None => { + self.tcx.sess.bug( + &format!("no type for node {}: {} in fcx", + id, self.tcx.map.node_to_string(id))); + } + } + } + + pub fn expr_ty(&self, ex: &hir::Expr) -> Ty<'tcx> { + match self.tables.borrow().node_types.get(&ex.id) { + Some(&t) => t, + None => { + self.tcx.sess.bug("no type for expr in fcx"); + } + } + } + + pub fn resolve_regions_and_report_errors(&self, + free_regions: &FreeRegionMap, + subject_node_id: ast::NodeId) { + let errors = self.region_vars.resolve_regions(free_regions, subject_node_id); + if !self.errors_since_creation() { + // As a heuristic, just skip reporting region errors + // altogether if other errors have been reported while + // this infcx was in use. This is totally hokey but + // otherwise we have a hard time separating legit region + // errors from silly ones. + self.report_region_errors(&errors); // see error_reporting.rs + } + } + + pub fn ty_to_string(&self, t: Ty<'tcx>) -> String { + self.resolve_type_vars_if_possible(&t).to_string() + } + + pub fn tys_to_string(&self, ts: &[Ty<'tcx>]) -> String { + let tstrs: Vec = ts.iter().map(|t| self.ty_to_string(*t)).collect(); + format!("({})", tstrs.join(", ")) + } + + pub fn trait_ref_to_string(&self, t: &ty::TraitRef<'tcx>) -> String { + self.resolve_type_vars_if_possible(t).to_string() + } + + pub fn shallow_resolve(&self, typ: Ty<'tcx>) -> Ty<'tcx> { + match typ.sty { + ty::TyInfer(ty::TyVar(v)) => { + // Not entirely obvious: if `typ` is a type variable, + // it can be resolved to an int/float variable, which + // can then be recursively resolved, hence the + // recursion. Note though that we prevent type + // variables from unifying to other type variables + // directly (though they may be embedded + // structurally), and we prevent cycles in any case, + // so this recursion should always be of very limited + // depth. + self.type_variables.borrow_mut() + .probe(v) + .map(|t| self.shallow_resolve(t)) + .unwrap_or(typ) + } + + ty::TyInfer(ty::IntVar(v)) => { + self.int_unification_table + .borrow_mut() + .probe(v) + .map(|v| v.to_type(self.tcx)) + .unwrap_or(typ) + } + + ty::TyInfer(ty::FloatVar(v)) => { + self.float_unification_table + .borrow_mut() + .probe(v) + .map(|v| v.to_type(self.tcx)) + .unwrap_or(typ) + } + + _ => { + typ + } + } + } + + pub fn resolve_type_vars_if_possible(&self, value: &T) -> T + where T: TypeFoldable<'tcx> + { + /*! + * Where possible, replaces type/int/float variables in + * `value` with their final value. Note that region variables + * are unaffected. If a type variable has not been unified, it + * is left as is. This is an idempotent operation that does + * not affect inference state in any way and so you can do it + * at will. + */ + + if !value.needs_infer() { + return value.clone(); // avoid duplicated subst-folding + } + let mut r = resolve::OpportunisticTypeResolver::new(self); + value.fold_with(&mut r) + } + + pub fn resolve_type_and_region_vars_if_possible(&self, value: &T) -> T + where T: TypeFoldable<'tcx> + { + let mut r = resolve::OpportunisticTypeAndRegionResolver::new(self); + value.fold_with(&mut r) + } + + /// Resolves all type variables in `t` and then, if any were left + /// unresolved, substitutes an error type. This is used after the + /// main checking when doing a second pass before writeback. The + /// justification is that writeback will produce an error for + /// these unconstrained type variables. + fn resolve_type_vars_or_error(&self, t: &Ty<'tcx>) -> mc::McResult> { + let ty = self.resolve_type_vars_if_possible(t); + if ty.references_error() || ty.is_ty_var() { + debug!("resolve_type_vars_or_error: error from {:?}", ty); + Err(()) + } else { + Ok(ty) + } + } + + pub fn fully_resolve>(&self, value: &T) -> FixupResult { + /*! + * Attempts to resolve all type/region variables in + * `value`. Region inference must have been run already (e.g., + * by calling `resolve_regions_and_report_errors`). If some + * variable was never unified, an `Err` results. + * + * This method is idempotent, but it not typically not invoked + * except during the writeback phase. + */ + + resolve::fully_resolve(self, value) + } + + // [Note-Type-error-reporting] + // An invariant is that anytime the expected or actual type is TyError (the special + // error type, meaning that an error occurred when typechecking this expression), + // this is a derived error. The error cascaded from another error (that was already + // reported), so it's not useful to display it to the user. + // The following four methods -- type_error_message_str, type_error_message_str_with_expected, + // type_error_message, and report_mismatched_types -- implement this logic. + // They check if either the actual or expected type is TyError, and don't print the error + // in this case. The typechecker should only ever report type errors involving mismatched + // types using one of these four methods, and should not call span_err directly for such + // errors. + pub fn type_error_message_str(&self, + sp: Span, + mk_msg: M, + actual_ty: String, + err: Option<&TypeError<'tcx>>) + where M: FnOnce(Option, String) -> String, + { + self.type_error_message_str_with_expected(sp, mk_msg, None, actual_ty, err) + } + + pub fn type_error_struct_str(&self, + sp: Span, + mk_msg: M, + actual_ty: String, + err: Option<&TypeError<'tcx>>) + -> DiagnosticBuilder<'tcx> + where M: FnOnce(Option, String) -> String, + { + self.type_error_struct_str_with_expected(sp, mk_msg, None, actual_ty, err) + } + + pub fn type_error_message_str_with_expected(&self, + sp: Span, + mk_msg: M, + expected_ty: Option>, + actual_ty: String, + err: Option<&TypeError<'tcx>>) + where M: FnOnce(Option, String) -> String, + { + self.type_error_struct_str_with_expected(sp, mk_msg, expected_ty, actual_ty, err) + .emit(); + } + + pub fn type_error_struct_str_with_expected(&self, + sp: Span, + mk_msg: M, + expected_ty: Option>, + actual_ty: String, + err: Option<&TypeError<'tcx>>) + -> DiagnosticBuilder<'tcx> + where M: FnOnce(Option, String) -> String, + { + debug!("hi! expected_ty = {:?}, actual_ty = {}", expected_ty, actual_ty); + + let resolved_expected = expected_ty.map(|e_ty| self.resolve_type_vars_if_possible(&e_ty)); + + if !resolved_expected.references_error() { + let error_str = err.map_or("".to_string(), |t_err| { + format!(" ({})", t_err) + }); + + let mut db = self.tcx.sess.struct_span_err(sp, &format!("{}{}", + mk_msg(resolved_expected.map(|t| self.ty_to_string(t)), actual_ty), + error_str)); + + if let Some(err) = err { + self.tcx.note_and_explain_type_err(&mut db, err, sp); + } + db + } else { + self.tcx.sess.diagnostic().struct_dummy() + } + } + + pub fn type_error_message(&self, + sp: Span, + mk_msg: M, + actual_ty: Ty<'tcx>, + err: Option<&TypeError<'tcx>>) + where M: FnOnce(String) -> String, + { + self.type_error_struct(sp, mk_msg, actual_ty, err).emit(); + } + + pub fn type_error_struct(&self, + sp: Span, + mk_msg: M, + actual_ty: Ty<'tcx>, + err: Option<&TypeError<'tcx>>) + -> DiagnosticBuilder<'tcx> + where M: FnOnce(String) -> String, + { + let actual_ty = self.resolve_type_vars_if_possible(&actual_ty); + + // Don't report an error if actual type is TyError. + if actual_ty.references_error() { + return self.tcx.sess.diagnostic().struct_dummy(); + } + + self.type_error_struct_str(sp, + move |_e, a| { mk_msg(a) }, + self.ty_to_string(actual_ty), err) + } + + pub fn report_mismatched_types(&self, + origin: TypeOrigin, + expected: Ty<'tcx>, + actual: Ty<'tcx>, + err: TypeError<'tcx>) { + let trace = TypeTrace { + origin: origin, + values: Types(ExpectedFound { + expected: expected, + found: actual + }) + }; + self.report_and_explain_type_error(trace, &err).emit(); + } + + pub fn report_conflicting_default_types(&self, + span: Span, + expected: type_variable::Default<'tcx>, + actual: type_variable::Default<'tcx>) { + let trace = TypeTrace { + origin: TypeOrigin::Misc(span), + values: Types(ExpectedFound { + expected: expected.ty, + found: actual.ty + }) + }; + + self.report_and_explain_type_error( + trace, + &TypeError::TyParamDefaultMismatch(ExpectedFound { + expected: expected, + found: actual + })) + .emit(); + } + + pub fn replace_late_bound_regions_with_fresh_var( + &self, + span: Span, + lbrct: LateBoundRegionConversionTime, + value: &ty::Binder) + -> (T, FnvHashMap) + where T : TypeFoldable<'tcx> + { + self.tcx.replace_late_bound_regions( + value, + |br| self.next_region_var(LateBoundRegion(span, br, lbrct))) + } + + /// See `verify_generic_bound` method in `region_inference` + pub fn verify_generic_bound(&self, + origin: SubregionOrigin<'tcx>, + kind: GenericKind<'tcx>, + a: ty::Region, + bound: VerifyBound) { + debug!("verify_generic_bound({:?}, {:?} <: {:?})", + kind, + a, + bound); + + self.region_vars.verify_generic_bound(origin, kind, a, bound); + } + + pub fn can_equate<'b,T>(&'b self, a: &T, b: &T) -> UnitResult<'tcx> + where T: Relate<'b,'tcx> + fmt::Debug + { + debug!("can_equate({:?}, {:?})", a, b); + self.probe(|_| { + // Gin up a dummy trace, since this won't be committed + // anyhow. We should make this typetrace stuff more + // generic so we don't have to do anything quite this + // terrible. + let e = self.tcx.types.err; + let trace = TypeTrace { + origin: TypeOrigin::Misc(codemap::DUMMY_SP), + values: Types(expected_found(true, e, e)) + }; + self.equate(true, trace).relate(a, b) + }).map(|_| ()) + } + + pub fn node_ty(&self, id: ast::NodeId) -> McResult> { + let ty = self.node_type(id); + self.resolve_type_vars_or_error(&ty) + } + + pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> McResult> { + let ty = self.adjust_expr_ty(expr, self.tables.borrow().adjustments.get(&expr.id)); + self.resolve_type_vars_or_error(&ty) + } + + pub fn tables_are_tcx_tables(&self) -> bool { + let tables: &RefCell = &self.tables; + let tcx_tables: &RefCell = &self.tcx.tables; + tables as *const _ == tcx_tables as *const _ + } + + pub fn type_moves_by_default(&self, ty: Ty<'tcx>, span: Span) -> bool { + let ty = self.resolve_type_vars_if_possible(&ty); + if ty.needs_infer() || + (ty.has_closure_types() && !self.tables_are_tcx_tables()) { + // this can get called from typeck (by euv), and moves_by_default + // rightly refuses to work with inference variables, but + // moves_by_default has a cache, which we want to use in other + // cases. + !traits::type_known_to_meet_builtin_bound(self, ty, ty::BoundCopy, span) + } else { + ty.moves_by_default(&self.parameter_environment, span) + } + } + + pub fn node_method_ty(&self, method_call: ty::MethodCall) + -> Option> { + self.tables + .borrow() + .method_map + .get(&method_call) + .map(|method| method.ty) + .map(|ty| self.resolve_type_vars_if_possible(&ty)) + } + + pub fn node_method_id(&self, method_call: ty::MethodCall) + -> Option { + self.tables + .borrow() + .method_map + .get(&method_call) + .map(|method| method.def_id) + } + + pub fn adjustments(&self) -> Ref>> { + fn project_adjustments<'a, 'tcx>(tables: &'a ty::Tables<'tcx>) + -> &'a NodeMap> { + &tables.adjustments + } + + Ref::map(self.tables.borrow(), project_adjustments) + } + + pub fn is_method_call(&self, id: ast::NodeId) -> bool { + self.tables.borrow().method_map.contains_key(&ty::MethodCall::expr(id)) + } + + pub fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option { + self.tcx.region_maps.temporary_scope(rvalue_id) + } + + pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option { + self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned() + } + + pub fn param_env<'b>(&'b self) -> &'b ty::ParameterEnvironment<'b,'tcx> { + &self.parameter_environment + } + + pub fn closure_kind(&self, + def_id: DefId) + -> Option + { + if def_id.is_local() { + self.tables.borrow().closure_kinds.get(&def_id).cloned() + } else { + // During typeck, ALL closures are local. But afterwards, + // during trans, we see closure ids from other traits. + // That may require loading the closure data out of the + // cstore. + Some(ty::Tables::closure_kind(&self.tables, self.tcx, def_id)) + } + } + + pub fn closure_type(&self, + def_id: DefId, + substs: &ty::ClosureSubsts<'tcx>) + -> ty::ClosureTy<'tcx> + { + let closure_ty = + ty::Tables::closure_type(self.tables, + self.tcx, + def_id, + substs); + + if self.normalize { + normalize_associated_type(&self.tcx, &closure_ty) + } else { + closure_ty + } + } +} + +impl<'tcx> TypeTrace<'tcx> { + pub fn span(&self) -> Span { + self.origin.span() + } + + pub fn types(origin: TypeOrigin, + a_is_expected: bool, + a: Ty<'tcx>, + b: Ty<'tcx>) + -> TypeTrace<'tcx> { + TypeTrace { + origin: origin, + values: Types(expected_found(a_is_expected, a, b)) + } + } + + pub fn dummy(tcx: &TyCtxt<'tcx>) -> TypeTrace<'tcx> { + TypeTrace { + origin: TypeOrigin::Misc(codemap::DUMMY_SP), + values: Types(ExpectedFound { + expected: tcx.types.err, + found: tcx.types.err, + }) + } + } +} + +impl<'tcx> fmt::Debug for TypeTrace<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "TypeTrace({:?})", self.origin) + } +} + +impl TypeOrigin { + pub fn span(&self) -> Span { + match *self { + TypeOrigin::MethodCompatCheck(span) => span, + TypeOrigin::ExprAssignable(span) => span, + TypeOrigin::Misc(span) => span, + TypeOrigin::RelateTraitRefs(span) => span, + TypeOrigin::RelateSelfType(span) => span, + TypeOrigin::RelateOutputImplTypes(span) => span, + TypeOrigin::MatchExpressionArm(match_span, _, _) => match_span, + TypeOrigin::IfExpression(span) => span, + TypeOrigin::IfExpressionWithNoElse(span) => span, + TypeOrigin::RangeExpression(span) => span, + TypeOrigin::EquatePredicate(span) => span, + } + } +} + +impl<'tcx> SubregionOrigin<'tcx> { + pub fn span(&self) -> Span { + match *self { + Subtype(ref a) => a.span(), + InfStackClosure(a) => a, + InvokeClosure(a) => a, + DerefPointer(a) => a, + FreeVariable(a, _) => a, + IndexSlice(a) => a, + RelateObjectBound(a) => a, + RelateParamBound(a, _) => a, + RelateRegionParamBound(a) => a, + RelateDefaultParamBound(a, _) => a, + Reborrow(a) => a, + ReborrowUpvar(a, _) => a, + DataBorrowed(_, a) => a, + ReferenceOutlivesReferent(_, a) => a, + ParameterInScope(_, a) => a, + ExprTypeIsNotInScope(_, a) => a, + BindingTypeIsNotValidAtDecl(a) => a, + CallRcvr(a) => a, + CallArg(a) => a, + CallReturn(a) => a, + Operand(a) => a, + AddrOf(a) => a, + AutoBorrow(a) => a, + SafeDestructor(a) => a, + } + } +} + +impl RegionVariableOrigin { + pub fn span(&self) -> Span { + match *self { + MiscVariable(a) => a, + PatternRegion(a) => a, + AddrOfRegion(a) => a, + Autoref(a) => a, + Coercion(a) => a, + EarlyBoundRegion(a, _) => a, + LateBoundRegion(a, _, _) => a, + BoundRegionInCoherence(_) => codemap::DUMMY_SP, + UpvarRegion(_, a) => a + } + } +} diff --git a/src/librustc/infer/region_inference/README.md b/src/librustc/infer/region_inference/README.md new file mode 100644 index 00000000000..80da861139b --- /dev/null +++ b/src/librustc/infer/region_inference/README.md @@ -0,0 +1,311 @@ +Region inference + +# Terminology + +Note that we use the terms region and lifetime interchangeably. + +# Introduction + +Region inference uses a somewhat more involved algorithm than type +inference. It is not the most efficient thing ever written though it +seems to work well enough in practice (famous last words). The reason +that we use a different algorithm is because, unlike with types, it is +impractical to hand-annotate with regions (in some cases, there aren't +even the requisite syntactic forms). So we have to get it right, and +it's worth spending more time on a more involved analysis. Moreover, +regions are a simpler case than types: they don't have aggregate +structure, for example. + +Unlike normal type inference, which is similar in spirit to H-M and thus +works progressively, the region type inference works by accumulating +constraints over the course of a function. Finally, at the end of +processing a function, we process and solve the constraints all at +once. + +The constraints are always of one of three possible forms: + +- `ConstrainVarSubVar(Ri, Rj)` states that region variable Ri must be + a subregion of Rj +- `ConstrainRegSubVar(R, Ri)` states that the concrete region R (which + must not be a variable) must be a subregion of the variable Ri +- `ConstrainVarSubReg(Ri, R)` states the variable Ri shoudl be less + than the concrete region R. This is kind of deprecated and ought to + be replaced with a verify (they essentially play the same role). + +In addition to constraints, we also gather up a set of "verifys" +(what, you don't think Verify is a noun? Get used to it my +friend!). These represent relations that must hold but which don't +influence inference proper. These take the form of: + +- `VerifyRegSubReg(Ri, Rj)` indicates that Ri <= Rj must hold, + where Rj is not an inference variable (and Ri may or may not contain + one). This doesn't influence inference because we will already have + inferred Ri to be as small as possible, so then we just test whether + that result was less than Rj or not. +- `VerifyGenericBound(R, Vb)` is a more complex expression which tests + that the region R must satisfy the bound `Vb`. The bounds themselves + may have structure like "must outlive one of the following regions" + or "must outlive ALL of the following regions. These bounds arise + from constraints like `T: 'a` -- if we know that `T: 'b` and `T: 'c` + (say, from where clauses), then we can conclude that `T: 'a` if `'b: + 'a` *or* `'c: 'a`. + +# Building up the constraints + +Variables and constraints are created using the following methods: + +- `new_region_var()` creates a new, unconstrained region variable; +- `make_subregion(Ri, Rj)` states that Ri is a subregion of Rj +- `lub_regions(Ri, Rj) -> Rk` returns a region Rk which is + the smallest region that is greater than both Ri and Rj +- `glb_regions(Ri, Rj) -> Rk` returns a region Rk which is + the greatest region that is smaller than both Ri and Rj + +The actual region resolution algorithm is not entirely +obvious, though it is also not overly complex. + +## Snapshotting + +It is also permitted to try (and rollback) changes to the graph. This +is done by invoking `start_snapshot()`, which returns a value. Then +later you can call `rollback_to()` which undoes the work. +Alternatively, you can call `commit()` which ends all snapshots. +Snapshots can be recursive---so you can start a snapshot when another +is in progress, but only the root snapshot can "commit". + +## The problem + +Basically our input is a directed graph where nodes can be divided +into two categories: region variables and concrete regions. Each edge +`R -> S` in the graph represents a constraint that the region `R` is a +subregion of the region `S`. + +Region variable nodes can have arbitrary degree. There is one region +variable node per region variable. + +Each concrete region node is associated with some, well, concrete +region: e.g., a free lifetime, or the region for a particular scope. +Note that there may be more than one concrete region node for a +particular region value. Moreover, because of how the graph is built, +we know that all concrete region nodes have either in-degree 1 or +out-degree 1. + +Before resolution begins, we build up the constraints in a hashmap +that maps `Constraint` keys to spans. During resolution, we construct +the actual `Graph` structure that we describe here. + +## Computing the values for region variables + +The algorithm is a simple dataflow algorithm. Each region variable +begins as empty. We iterate over the constraints, and for each constraint +we grow the relevant region variable to be as big as it must be to meet all the +constraints. This means the region variables can grow to be `'static` if +necessary. + +## Verification + +After all constraints are fully propoagated, we do a "verification" +step where we walk over the verify bounds and check that they are +satisfied. These bounds represent the "maximal" values that a region +variable can take on, basically. + +# The Region Hierarchy + +## Without closures + +Let's first consider the region hierarchy without thinking about +closures, because they add a lot of complications. The region +hierarchy *basically* mirrors the lexical structure of the code. +There is a region for every piece of 'evaluation' that occurs, meaning +every expression, block, and pattern (patterns are considered to +"execute" by testing the value they are applied to and creating any +relevant bindings). So, for example: + + fn foo(x: isize, y: isize) { // -+ + // +------------+ // | + // | +-----+ // | + // | +-+ +-+ +-+ // | + // | | | | | | | // | + // v v v v v v v // | + let z = x + y; // | + ... // | + } // -+ + + fn bar() { ... } + +In this example, there is a region for the fn body block as a whole, +and then a subregion for the declaration of the local variable. +Within that, there are sublifetimes for the assignment pattern and +also the expression `x + y`. The expression itself has sublifetimes +for evaluating `x` and `y`. + +## Function calls + +Function calls are a bit tricky. I will describe how we handle them +*now* and then a bit about how we can improve them (Issue #6268). + +Consider a function call like `func(expr1, expr2)`, where `func`, +`arg1`, and `arg2` are all arbitrary expressions. Currently, +we construct a region hierarchy like: + + +----------------+ + | | + +--+ +---+ +---+| + v v v v v vv + func(expr1, expr2) + +Here you can see that the call as a whole has a region and the +function plus arguments are subregions of that. As a side-effect of +this, we get a lot of spurious errors around nested calls, in +particular when combined with `&mut` functions. For example, a call +like this one + + self.foo(self.bar()) + +where both `foo` and `bar` are `&mut self` functions will always yield +an error. + +Here is a more involved example (which is safe) so we can see what's +going on: + + struct Foo { f: usize, g: usize } + ... + fn add(p: &mut usize, v: usize) { + *p += v; + } + ... + fn inc(p: &mut usize) -> usize { + *p += 1; *p + } + fn weird() { + let mut x: Box = box Foo { ... }; + 'a: add(&mut (*x).f, + 'b: inc(&mut (*x).f)) // (..) + } + +The important part is the line marked `(..)` which contains a call to +`add()`. The first argument is a mutable borrow of the field `f`. The +second argument also borrows the field `f`. Now, in the current borrow +checker, the first borrow is given the lifetime of the call to +`add()`, `'a`. The second borrow is given the lifetime of `'b` of the +call to `inc()`. Because `'b` is considered to be a sublifetime of +`'a`, an error is reported since there are two co-existing mutable +borrows of the same data. + +However, if we were to examine the lifetimes a bit more carefully, we +can see that this error is unnecessary. Let's examine the lifetimes +involved with `'a` in detail. We'll break apart all the steps involved +in a call expression: + + 'a: { + 'a_arg1: let a_temp1: ... = add; + 'a_arg2: let a_temp2: &'a mut usize = &'a mut (*x).f; + 'a_arg3: let a_temp3: usize = { + let b_temp1: ... = inc; + let b_temp2: &'b = &'b mut (*x).f; + 'b_call: b_temp1(b_temp2) + }; + 'a_call: a_temp1(a_temp2, a_temp3) // (**) + } + +Here we see that the lifetime `'a` includes a number of substatements. +In particular, there is this lifetime I've called `'a_call` that +corresponds to the *actual execution of the function `add()`*, after +all arguments have been evaluated. There is a corresponding lifetime +`'b_call` for the execution of `inc()`. If we wanted to be precise +about it, the lifetime of the two borrows should be `'a_call` and +`'b_call` respectively, since the references that were created +will not be dereferenced except during the execution itself. + +However, this model by itself is not sound. The reason is that +while the two references that are created will never be used +simultaneously, it is still true that the first reference is +*created* before the second argument is evaluated, and so even though +it will not be *dereferenced* during the evaluation of the second +argument, it can still be *invalidated* by that evaluation. Consider +this similar but unsound example: + + struct Foo { f: usize, g: usize } + ... + fn add(p: &mut usize, v: usize) { + *p += v; + } + ... + fn consume(x: Box) -> usize { + x.f + x.g + } + fn weird() { + let mut x: Box = box Foo { ... }; + 'a: add(&mut (*x).f, consume(x)) // (..) + } + +In this case, the second argument to `add` actually consumes `x`, thus +invalidating the first argument. + +So, for now, we exclude the `call` lifetimes from our model. +Eventually I would like to include them, but we will have to make the +borrow checker handle this situation correctly. In particular, if +there is a reference created whose lifetime does not enclose +the borrow expression, we must issue sufficient restrictions to ensure +that the pointee remains valid. + +## Modeling closures + +Integrating closures properly into the model is a bit of +work-in-progress. In an ideal world, we would model closures as +closely as possible after their desugared equivalents. That is, a +closure type would be modeled as a struct, and the region hierarchy of +different closure bodies would be completely distinct from all other +fns. We are generally moving in that direction but there are +complications in terms of the implementation. + +In practice what we currently do is somewhat different. The basis for +the current approach is the observation that the only time that +regions from distinct fn bodies interact with one another is through +an upvar or the type of a fn parameter (since closures live in the fn +body namespace, they can in fact have fn parameters whose types +include regions from the surrounding fn body). For these cases, there +are separate mechanisms which ensure that the regions that appear in +upvars/parameters outlive the dynamic extent of each call to the +closure: + +1. Types must outlive the region of any expression where they are used. + For a closure type `C` to outlive a region `'r`, that implies that the + types of all its upvars must outlive `'r`. +2. Parameters must outlive the region of any fn that they are passed to. + +Therefore, we can -- sort of -- assume that any region from an +enclosing fns is larger than any region from one of its enclosed +fn. And that is precisely what we do: when building the region +hierarchy, each region lives in its own distinct subtree, but if we +are asked to compute the `LUB(r1, r2)` of two regions, and those +regions are in disjoint subtrees, we compare the lexical nesting of +the two regions. + +*Ideas for improving the situation:* (FIXME #3696) The correctness +argument here is subtle and a bit hand-wavy. The ideal, as stated +earlier, would be to model things in such a way that it corresponds +more closely to the desugared code. The best approach for doing this +is a bit unclear: it may in fact be possible to *actually* desugar +before we start, but I don't think so. The main option that I've been +thinking through is imposing a "view shift" as we enter the fn body, +so that regions appearing in the types of fn parameters and upvars are +translated from being regions in the outer fn into free region +parameters, just as they would be if we applied the desugaring. The +challenge here is that type inference may not have fully run, so the +types may not be fully known: we could probably do this translation +lazilly, as type variables are instantiated. We would also have to +apply a kind of inverse translation to the return value. This would be +a good idea anyway, as right now it is possible for free regions +instantiated within the closure to leak into the parent: this +currently leads to type errors, since those regions cannot outlive any +expressions within the parent hierarchy. Much like the current +handling of closures, there are no known cases where this leads to a +type-checking accepting incorrect code (though it sometimes rejects +what might be considered correct code; see rust-lang/rust#22557), but +it still doesn't feel like the right approach. + +### Skolemization + +For a discussion on skolemization and higher-ranked subtyping, please +see the module `middle::infer::higher_ranked::doc`. diff --git a/src/librustc/infer/region_inference/graphviz.rs b/src/librustc/infer/region_inference/graphviz.rs new file mode 100644 index 00000000000..e561f4a3548 --- /dev/null +++ b/src/librustc/infer/region_inference/graphviz.rs @@ -0,0 +1,273 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module provides linkage between libgraphviz traits and +//! `rustc::middle::typeck::infer::region_inference`, generating a +//! rendering of the graph represented by the list of `Constraint` +//! instances (which make up the edges of the graph), as well as the +//! origin for each constraint (which are attached to the labels on +//! each edge). + +/// For clarity, rename the graphviz crate locally to dot. +use graphviz as dot; + +use ty::{self, TyCtxt}; +use middle::region::CodeExtent; +use super::Constraint; +use infer::SubregionOrigin; +use infer::region_inference::RegionVarBindings; +use util::nodemap::{FnvHashMap, FnvHashSet}; + +use std::borrow::Cow; +use std::collections::hash_map::Entry::Vacant; +use std::env; +use std::fs::File; +use std::io; +use std::io::prelude::*; +use std::sync::atomic::{AtomicBool, Ordering}; +use syntax::ast; + +fn print_help_message() { + println!("\ +-Z print-region-graph by default prints a region constraint graph for every \n\ +function body, to the path `/tmp/constraints.nodeXXX.dot`, where the XXX is \n\ +replaced with the node id of the function under analysis. \n\ + \n\ +To select one particular function body, set `RUST_REGION_GRAPH_NODE=XXX`, \n\ +where XXX is the node id desired. \n\ + \n\ +To generate output to some path other than the default \n\ +`/tmp/constraints.nodeXXX.dot`, set `RUST_REGION_GRAPH=/path/desired.dot`; \n\ +occurrences of the character `%` in the requested path will be replaced with\n\ +the node id of the function under analysis. \n\ + \n\ +(Since you requested help via RUST_REGION_GRAPH=help, no region constraint \n\ +graphs will be printed. \n\ +"); +} + +pub fn maybe_print_constraints_for<'a, 'tcx>(region_vars: &RegionVarBindings<'a, 'tcx>, + subject_node: ast::NodeId) { + let tcx = region_vars.tcx; + + if !region_vars.tcx.sess.opts.debugging_opts.print_region_graph { + return; + } + + let requested_node: Option = env::var("RUST_REGION_GRAPH_NODE") + .ok() + .and_then(|s| s.parse().ok()); + + if requested_node.is_some() && requested_node != Some(subject_node) { + return; + } + + let requested_output = env::var("RUST_REGION_GRAPH"); + debug!("requested_output: {:?} requested_node: {:?}", + requested_output, + requested_node); + + let output_path = { + let output_template = match requested_output { + Ok(ref s) if s == "help" => { + static PRINTED_YET: AtomicBool = AtomicBool::new(false); + if !PRINTED_YET.load(Ordering::SeqCst) { + print_help_message(); + PRINTED_YET.store(true, Ordering::SeqCst); + } + return; + } + + Ok(other_path) => other_path, + Err(_) => "/tmp/constraints.node%.dot".to_string(), + }; + + if output_template.is_empty() { + tcx.sess.bug("empty string provided as RUST_REGION_GRAPH"); + } + + if output_template.contains('%') { + let mut new_str = String::new(); + for c in output_template.chars() { + if c == '%' { + new_str.push_str(&subject_node.to_string()); + } else { + new_str.push(c); + } + } + new_str + } else { + output_template + } + }; + + let constraints = &*region_vars.constraints.borrow(); + match dump_region_constraints_to(tcx, constraints, &output_path) { + Ok(()) => {} + Err(e) => { + let msg = format!("io error dumping region constraints: {}", e); + region_vars.tcx.sess.err(&msg) + } + } +} + +struct ConstraintGraph<'a, 'tcx: 'a> { + tcx: &'a TyCtxt<'tcx>, + graph_name: String, + map: &'a FnvHashMap>, + node_ids: FnvHashMap, +} + +#[derive(Clone, Hash, PartialEq, Eq, Debug, Copy)] +enum Node { + RegionVid(ty::RegionVid), + Region(ty::Region), +} + +// type Edge = Constraint; +#[derive(Clone, PartialEq, Eq, Debug, Copy)] +enum Edge { + Constraint(Constraint), + EnclScope(CodeExtent, CodeExtent), +} + +impl<'a, 'tcx> ConstraintGraph<'a, 'tcx> { + fn new(tcx: &'a TyCtxt<'tcx>, + name: String, + map: &'a ConstraintMap<'tcx>) + -> ConstraintGraph<'a, 'tcx> { + let mut i = 0; + let mut node_ids = FnvHashMap(); + { + let mut add_node = |node| { + if let Vacant(e) = node_ids.entry(node) { + e.insert(i); + i += 1; + } + }; + + for (n1, n2) in map.keys().map(|c| constraint_to_nodes(c)) { + add_node(n1); + add_node(n2); + } + + tcx.region_maps.each_encl_scope(|sub, sup| { + add_node(Node::Region(ty::ReScope(*sub))); + add_node(Node::Region(ty::ReScope(*sup))); + }); + } + + ConstraintGraph { + tcx: tcx, + graph_name: name, + map: map, + node_ids: node_ids, + } + } +} + +impl<'a, 'tcx> dot::Labeller<'a> for ConstraintGraph<'a, 'tcx> { + type Node = Node; + type Edge = Edge; + fn graph_id(&self) -> dot::Id { + dot::Id::new(&*self.graph_name).unwrap() + } + fn node_id(&self, n: &Node) -> dot::Id { + let node_id = match self.node_ids.get(n) { + Some(node_id) => node_id, + None => panic!("no node_id found for node: {:?}", n), + }; + let name = || format!("node_{}", node_id); + match dot::Id::new(name()) { + Ok(id) => id, + Err(_) => { + panic!("failed to create graphviz node identified by {}", name()); + } + } + } + fn node_label(&self, n: &Node) -> dot::LabelText { + match *n { + Node::RegionVid(n_vid) => dot::LabelText::label(format!("{:?}", n_vid)), + Node::Region(n_rgn) => dot::LabelText::label(format!("{:?}", n_rgn)), + } + } + fn edge_label(&self, e: &Edge) -> dot::LabelText { + match *e { + Edge::Constraint(ref c) => + dot::LabelText::label(format!("{:?}", self.map.get(c).unwrap())), + Edge::EnclScope(..) => dot::LabelText::label(format!("(enclosed)")), + } + } +} + +fn constraint_to_nodes(c: &Constraint) -> (Node, Node) { + match *c { + Constraint::ConstrainVarSubVar(rv_1, rv_2) => + (Node::RegionVid(rv_1), Node::RegionVid(rv_2)), + Constraint::ConstrainRegSubVar(r_1, rv_2) => (Node::Region(r_1), Node::RegionVid(rv_2)), + Constraint::ConstrainVarSubReg(rv_1, r_2) => (Node::RegionVid(rv_1), Node::Region(r_2)), + } +} + +fn edge_to_nodes(e: &Edge) -> (Node, Node) { + match *e { + Edge::Constraint(ref c) => constraint_to_nodes(c), + Edge::EnclScope(sub, sup) => { + (Node::Region(ty::ReScope(sub)), + Node::Region(ty::ReScope(sup))) + } + } +} + +impl<'a, 'tcx> dot::GraphWalk<'a> for ConstraintGraph<'a, 'tcx> { + type Node = Node; + type Edge = Edge; + fn nodes(&self) -> dot::Nodes { + let mut set = FnvHashSet(); + for node in self.node_ids.keys() { + set.insert(*node); + } + debug!("constraint graph has {} nodes", set.len()); + set.into_iter().collect() + } + fn edges(&self) -> dot::Edges { + debug!("constraint graph has {} edges", self.map.len()); + let mut v: Vec<_> = self.map.keys().map(|e| Edge::Constraint(*e)).collect(); + self.tcx.region_maps.each_encl_scope(|sub, sup| v.push(Edge::EnclScope(*sub, *sup))); + debug!("region graph has {} edges", v.len()); + Cow::Owned(v) + } + fn source(&self, edge: &Edge) -> Node { + let (n1, _) = edge_to_nodes(edge); + debug!("edge {:?} has source {:?}", edge, n1); + n1 + } + fn target(&self, edge: &Edge) -> Node { + let (_, n2) = edge_to_nodes(edge); + debug!("edge {:?} has target {:?}", edge, n2); + n2 + } +} + +pub type ConstraintMap<'tcx> = FnvHashMap>; + +fn dump_region_constraints_to<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>, + map: &ConstraintMap<'tcx>, + path: &str) + -> io::Result<()> { + debug!("dump_region_constraints map (len: {}) path: {}", + map.len(), + path); + let g = ConstraintGraph::new(tcx, format!("region_constraints"), map); + debug!("dump_region_constraints calling render"); + let mut v = Vec::new(); + dot::render(&g, &mut v).unwrap(); + File::create(path).and_then(|mut f| f.write_all(&v)) +} diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs new file mode 100644 index 00000000000..2b74dcb40c4 --- /dev/null +++ b/src/librustc/infer/region_inference/mod.rs @@ -0,0 +1,1453 @@ +// Copyright 2012-2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! See README.md + +pub use self::Constraint::*; +pub use self::Verify::*; +pub use self::UndoLogEntry::*; +pub use self::CombineMapType::*; +pub use self::RegionResolutionError::*; +pub use self::VarValue::*; + +use super::{RegionVariableOrigin, SubregionOrigin, MiscVariable}; +use super::unify_key; + +use rustc_data_structures::graph::{self, Direction, NodeIndex}; +use rustc_data_structures::unify::{self, UnificationTable}; +use middle::free_region::FreeRegionMap; +use ty::{self, Ty, TyCtxt}; +use ty::{BoundRegion, Region, RegionVid}; +use ty::{ReEmpty, ReStatic, ReFree, ReEarlyBound}; +use ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh}; +use util::common::indenter; +use util::nodemap::{FnvHashMap, FnvHashSet}; + +use std::cell::{Cell, RefCell}; +use std::cmp::Ordering::{self, Less, Greater, Equal}; +use std::fmt; +use std::u32; +use syntax::ast; + +mod graphviz; + +// A constraint that influences the inference process. +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum Constraint { + // One region variable is subregion of another + ConstrainVarSubVar(RegionVid, RegionVid), + + // Concrete region is subregion of region variable + ConstrainRegSubVar(Region, RegionVid), + + // Region variable is subregion of concrete region + // + // FIXME(#29436) -- should be remove in favor of a Verify + ConstrainVarSubReg(RegionVid, Region), +} + +// Something we have to verify after region inference is done, but +// which does not directly influence the inference process +pub enum Verify<'tcx> { + // VerifyRegSubReg(a, b): Verify that `a <= b`. Neither `a` nor + // `b` are inference variables. + VerifyRegSubReg(SubregionOrigin<'tcx>, Region, Region), + + // VerifyGenericBound(T, _, R, RS): The parameter type `T` (or + // associated type) must outlive the region `R`. `T` is known to + // outlive `RS`. Therefore verify that `R <= RS[i]` for some + // `i`. Inference variables may be involved (but this verification + // step doesn't influence inference). + VerifyGenericBound(GenericKind<'tcx>, SubregionOrigin<'tcx>, Region, VerifyBound), +} + +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum GenericKind<'tcx> { + Param(ty::ParamTy), + Projection(ty::ProjectionTy<'tcx>), +} + +// When we introduce a verification step, we wish to test that a +// particular region (let's call it `'min`) meets some bound. +// The bound is described the by the following grammar: +#[derive(Debug)] +pub enum VerifyBound { + // B = exists {R} --> some 'r in {R} must outlive 'min + // + // Put another way, the subject value is known to outlive all + // regions in {R}, so if any of those outlives 'min, then the + // bound is met. + AnyRegion(Vec), + + // B = forall {R} --> all 'r in {R} must outlive 'min + // + // Put another way, the subject value is known to outlive some + // region in {R}, so if all of those outlives 'min, then the bound + // is met. + AllRegions(Vec), + + // B = exists {B} --> 'min must meet some bound b in {B} + AnyBound(Vec), + + // B = forall {B} --> 'min must meet all bounds b in {B} + AllBounds(Vec), +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct TwoRegions { + a: Region, + b: Region, +} + +#[derive(Copy, Clone, PartialEq)] +pub enum UndoLogEntry { + OpenSnapshot, + CommitedSnapshot, + AddVar(RegionVid), + AddConstraint(Constraint), + AddVerify(usize), + AddGiven(ty::FreeRegion, ty::RegionVid), + AddCombination(CombineMapType, TwoRegions), +} + +#[derive(Copy, Clone, PartialEq)] +pub enum CombineMapType { + Lub, + Glb, +} + +#[derive(Clone, Debug)] +pub enum RegionResolutionError<'tcx> { + /// `ConcreteFailure(o, a, b)`: + /// + /// `o` requires that `a <= b`, but this does not hold + ConcreteFailure(SubregionOrigin<'tcx>, Region, Region), + + /// `GenericBoundFailure(p, s, a) + /// + /// The parameter/associated-type `p` must be known to outlive the lifetime + /// `a` (but none of the known bounds are sufficient). + GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region), + + /// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`: + /// + /// Could not infer a value for `v` because `sub_r <= v` (due to + /// `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and + /// `sub_r <= sup_r` does not hold. + SubSupConflict(RegionVariableOrigin, + SubregionOrigin<'tcx>, + Region, + SubregionOrigin<'tcx>, + Region), + + /// For subsets of `ConcreteFailure` and `SubSupConflict`, we can derive + /// more specific errors message by suggesting to the user where they + /// should put a lifetime. In those cases we process and put those errors + /// into `ProcessedErrors` before we do any reporting. + ProcessedErrors(Vec>, + Vec), +} + +#[derive(Clone, Debug)] +pub enum ProcessedErrorOrigin<'tcx> { + ConcreteFailure(SubregionOrigin<'tcx>, Region, Region), + VariableFailure(RegionVariableOrigin), +} + +/// SameRegions is used to group regions that we think are the same and would +/// like to indicate so to the user. +/// For example, the following function +/// ``` +/// struct Foo { bar: i32 } +/// fn foo2<'a, 'b>(x: &'a Foo) -> &'b i32 { +/// &x.bar +/// } +/// ``` +/// would report an error because we expect 'a and 'b to match, and so we group +/// 'a and 'b together inside a SameRegions struct +#[derive(Clone, Debug)] +pub struct SameRegions { + pub scope_id: ast::NodeId, + pub regions: Vec, +} + +impl SameRegions { + pub fn contains(&self, other: &BoundRegion) -> bool { + self.regions.contains(other) + } + + pub fn push(&mut self, other: BoundRegion) { + self.regions.push(other); + } +} + +pub type CombineMap = FnvHashMap; + +pub struct RegionVarBindings<'a, 'tcx: 'a> { + tcx: &'a TyCtxt<'tcx>, + var_origins: RefCell>, + + // Constraints of the form `A <= B` introduced by the region + // checker. Here at least one of `A` and `B` must be a region + // variable. + constraints: RefCell>>, + + // A "verify" is something that we need to verify after inference is + // done, but which does not directly affect inference in any way. + // + // An example is a `A <= B` where neither `A` nor `B` are + // inference variables. + verifys: RefCell>>, + + // A "given" is a relationship that is known to hold. In particular, + // we often know from closure fn signatures that a particular free + // region must be a subregion of a region variable: + // + // foo.iter().filter(<'a> |x: &'a &'b T| ...) + // + // In situations like this, `'b` is in fact a region variable + // introduced by the call to `iter()`, and `'a` is a bound region + // on the closure (as indicated by the `<'a>` prefix). If we are + // naive, we wind up inferring that `'b` must be `'static`, + // because we require that it be greater than `'a` and we do not + // know what `'a` is precisely. + // + // This hashmap is used to avoid that naive scenario. Basically we + // record the fact that `'a <= 'b` is implied by the fn signature, + // and then ignore the constraint when solving equations. This is + // a bit of a hack but seems to work. + givens: RefCell>, + + lubs: RefCell, + glbs: RefCell, + skolemization_count: Cell, + bound_count: Cell, + + // The undo log records actions that might later be undone. + // + // Note: when the undo_log is empty, we are not actively + // snapshotting. When the `start_snapshot()` method is called, we + // push an OpenSnapshot entry onto the list to indicate that we + // are now actively snapshotting. The reason for this is that + // otherwise we end up adding entries for things like the lower + // bound on a variable and so forth, which can never be rolled + // back. + undo_log: RefCell>, + unification_table: RefCell>, + + // This contains the results of inference. It begins as an empty + // option and only acquires a value after inference is complete. + values: RefCell>>, +} + +pub struct RegionSnapshot { + length: usize, + region_snapshot: unify::Snapshot, + skolemization_count: u32, +} + +impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { + pub fn new(tcx: &'a TyCtxt<'tcx>) -> RegionVarBindings<'a, 'tcx> { + RegionVarBindings { + tcx: tcx, + var_origins: RefCell::new(Vec::new()), + values: RefCell::new(None), + constraints: RefCell::new(FnvHashMap()), + verifys: RefCell::new(Vec::new()), + givens: RefCell::new(FnvHashSet()), + lubs: RefCell::new(FnvHashMap()), + glbs: RefCell::new(FnvHashMap()), + skolemization_count: Cell::new(0), + bound_count: Cell::new(0), + undo_log: RefCell::new(Vec::new()), + unification_table: RefCell::new(UnificationTable::new()), + } + } + + fn in_snapshot(&self) -> bool { + !self.undo_log.borrow().is_empty() + } + + pub fn start_snapshot(&self) -> RegionSnapshot { + let length = self.undo_log.borrow().len(); + debug!("RegionVarBindings: start_snapshot({})", length); + self.undo_log.borrow_mut().push(OpenSnapshot); + RegionSnapshot { + length: length, + region_snapshot: self.unification_table.borrow_mut().snapshot(), + skolemization_count: self.skolemization_count.get(), + } + } + + pub fn commit(&self, snapshot: RegionSnapshot) { + debug!("RegionVarBindings: commit({})", snapshot.length); + assert!(self.undo_log.borrow().len() > snapshot.length); + assert!((*self.undo_log.borrow())[snapshot.length] == OpenSnapshot); + + let mut undo_log = self.undo_log.borrow_mut(); + if snapshot.length == 0 { + undo_log.truncate(0); + } else { + (*undo_log)[snapshot.length] = CommitedSnapshot; + } + self.skolemization_count.set(snapshot.skolemization_count); + self.unification_table.borrow_mut().commit(snapshot.region_snapshot); + } + + pub fn rollback_to(&self, snapshot: RegionSnapshot) { + debug!("RegionVarBindings: rollback_to({:?})", snapshot); + let mut undo_log = self.undo_log.borrow_mut(); + assert!(undo_log.len() > snapshot.length); + assert!((*undo_log)[snapshot.length] == OpenSnapshot); + while undo_log.len() > snapshot.length + 1 { + match undo_log.pop().unwrap() { + OpenSnapshot => { + panic!("Failure to observe stack discipline"); + } + CommitedSnapshot => {} + AddVar(vid) => { + let mut var_origins = self.var_origins.borrow_mut(); + var_origins.pop().unwrap(); + assert_eq!(var_origins.len(), vid.index as usize); + } + AddConstraint(ref constraint) => { + self.constraints.borrow_mut().remove(constraint); + } + AddVerify(index) => { + self.verifys.borrow_mut().pop(); + assert_eq!(self.verifys.borrow().len(), index); + } + AddGiven(sub, sup) => { + self.givens.borrow_mut().remove(&(sub, sup)); + } + AddCombination(Glb, ref regions) => { + self.glbs.borrow_mut().remove(regions); + } + AddCombination(Lub, ref regions) => { + self.lubs.borrow_mut().remove(regions); + } + } + } + let c = undo_log.pop().unwrap(); + assert!(c == OpenSnapshot); + self.skolemization_count.set(snapshot.skolemization_count); + self.unification_table.borrow_mut() + .rollback_to(snapshot.region_snapshot); + } + + pub fn num_vars(&self) -> u32 { + let len = self.var_origins.borrow().len(); + // enforce no overflow + assert!(len as u32 as usize == len); + len as u32 + } + + pub fn new_region_var(&self, origin: RegionVariableOrigin) -> RegionVid { + let vid = RegionVid { index: self.num_vars() }; + self.var_origins.borrow_mut().push(origin.clone()); + + let u_vid = self.unification_table.borrow_mut().new_key( + unify_key::RegionVidKey { min_vid: vid } + ); + assert_eq!(vid, u_vid); + if self.in_snapshot() { + self.undo_log.borrow_mut().push(AddVar(vid)); + } + debug!("created new region variable {:?} with origin {:?}", + vid, + origin); + return vid; + } + + /// Creates a new skolemized region. Skolemized regions are fresh + /// regions used when performing higher-ranked computations. They + /// must be used in a very particular way and are never supposed + /// to "escape" out into error messages or the code at large. + /// + /// The idea is to always create a snapshot. Skolemized regions + /// can be created in the context of this snapshot, but once the + /// snapshot is committed or rolled back, their numbers will be + /// recycled, so you must be finished with them. See the extensive + /// comments in `higher_ranked.rs` to see how it works (in + /// particular, the subtyping comparison). + /// + /// The `snapshot` argument to this function is not really used; + /// it's just there to make it explicit which snapshot bounds the + /// skolemized region that results. + pub fn new_skolemized(&self, br: ty::BoundRegion, snapshot: &RegionSnapshot) -> Region { + assert!(self.in_snapshot()); + assert!(self.undo_log.borrow()[snapshot.length] == OpenSnapshot); + + let sc = self.skolemization_count.get(); + self.skolemization_count.set(sc + 1); + ReSkolemized(ty::SkolemizedRegionVid { index: sc }, br) + } + + pub fn new_bound(&self, debruijn: ty::DebruijnIndex) -> Region { + // Creates a fresh bound variable for use in GLB computations. + // See discussion of GLB computation in the large comment at + // the top of this file for more details. + // + // This computation is potentially wrong in the face of + // rollover. It's conceivable, if unlikely, that one might + // wind up with accidental capture for nested functions in + // that case, if the outer function had bound regions created + // a very long time before and the inner function somehow + // wound up rolling over such that supposedly fresh + // identifiers were in fact shadowed. For now, we just assert + // that there is no rollover -- eventually we should try to be + // robust against this possibility, either by checking the set + // of bound identifiers that appear in a given expression and + // ensure that we generate one that is distinct, or by + // changing the representation of bound regions in a fn + // declaration + + let sc = self.bound_count.get(); + self.bound_count.set(sc + 1); + + if sc >= self.bound_count.get() { + self.tcx.sess.bug("rollover in RegionInference new_bound()"); + } + + ReLateBound(debruijn, BrFresh(sc)) + } + + fn values_are_none(&self) -> bool { + self.values.borrow().is_none() + } + + fn add_constraint(&self, constraint: Constraint, origin: SubregionOrigin<'tcx>) { + // cannot add constraints once regions are resolved + assert!(self.values_are_none()); + + debug!("RegionVarBindings: add_constraint({:?})", constraint); + + if self.constraints.borrow_mut().insert(constraint, origin).is_none() { + if self.in_snapshot() { + self.undo_log.borrow_mut().push(AddConstraint(constraint)); + } + } + } + + fn add_verify(&self, verify: Verify<'tcx>) { + // cannot add verifys once regions are resolved + assert!(self.values_are_none()); + + debug!("RegionVarBindings: add_verify({:?})", verify); + + // skip no-op cases known to be satisfied + match verify { + VerifyGenericBound(_, _, _, VerifyBound::AllBounds(ref bs)) if bs.len() == 0 => { + return; + } + _ => {} + } + + let mut verifys = self.verifys.borrow_mut(); + let index = verifys.len(); + verifys.push(verify); + if self.in_snapshot() { + self.undo_log.borrow_mut().push(AddVerify(index)); + } + } + + pub fn add_given(&self, sub: ty::FreeRegion, sup: ty::RegionVid) { + // cannot add givens once regions are resolved + assert!(self.values_are_none()); + + let mut givens = self.givens.borrow_mut(); + if givens.insert((sub, sup)) { + debug!("add_given({:?} <= {:?})", sub, sup); + + self.undo_log.borrow_mut().push(AddGiven(sub, sup)); + } + } + + pub fn make_eqregion(&self, origin: SubregionOrigin<'tcx>, sub: Region, sup: Region) { + if sub != sup { + // Eventually, it would be nice to add direct support for + // equating regions. + self.make_subregion(origin.clone(), sub, sup); + self.make_subregion(origin, sup, sub); + + if let (ty::ReVar(sub), ty::ReVar(sup)) = (sub, sup) { + self.unification_table.borrow_mut().union(sub, sup); + } + } + } + + pub fn make_subregion(&self, origin: SubregionOrigin<'tcx>, sub: Region, sup: Region) { + // cannot add constraints once regions are resolved + assert!(self.values_are_none()); + + debug!("RegionVarBindings: make_subregion({:?}, {:?}) due to {:?}", + sub, + sup, + origin); + + match (sub, sup) { + (ReEarlyBound(..), _) | + (ReLateBound(..), _) | + (_, ReEarlyBound(..)) | + (_, ReLateBound(..)) => { + self.tcx.sess.span_bug(origin.span(), + &format!("cannot relate bound region: {:?} <= {:?}", + sub, + sup)); + } + (_, ReStatic) => { + // all regions are subregions of static, so we can ignore this + } + (ReVar(sub_id), ReVar(sup_id)) => { + self.add_constraint(ConstrainVarSubVar(sub_id, sup_id), origin); + } + (r, ReVar(sup_id)) => { + self.add_constraint(ConstrainRegSubVar(r, sup_id), origin); + } + (ReVar(sub_id), r) => { + self.add_constraint(ConstrainVarSubReg(sub_id, r), origin); + } + _ => { + self.add_verify(VerifyRegSubReg(origin, sub, sup)); + } + } + } + + /// See `Verify::VerifyGenericBound` + pub fn verify_generic_bound(&self, + origin: SubregionOrigin<'tcx>, + kind: GenericKind<'tcx>, + sub: Region, + bound: VerifyBound) { + self.add_verify(VerifyGenericBound(kind, origin, sub, bound)); + } + + pub fn lub_regions(&self, origin: SubregionOrigin<'tcx>, a: Region, b: Region) -> Region { + // cannot add constraints once regions are resolved + assert!(self.values_are_none()); + + debug!("RegionVarBindings: lub_regions({:?}, {:?})", a, b); + if a == ty::ReStatic || b == ty::ReStatic { + ReStatic // nothing lives longer than static + } else if a == b { + a // LUB(a,a) = a + } else { + self.combine_vars(Lub, a, b, origin.clone(), |this, old_r, new_r| { + this.make_subregion(origin.clone(), old_r, new_r) + }) + } + } + + pub fn glb_regions(&self, origin: SubregionOrigin<'tcx>, a: Region, b: Region) -> Region { + // cannot add constraints once regions are resolved + assert!(self.values_are_none()); + + debug!("RegionVarBindings: glb_regions({:?}, {:?})", a, b); + match (a, b) { + (ReStatic, r) | (r, ReStatic) => { + r // static lives longer than everything else + } + + _ if a == b => { + a // GLB(a,a) = a + } + + _ => { + self.combine_vars(Glb, a, b, origin.clone(), |this, old_r, new_r| { + this.make_subregion(origin.clone(), new_r, old_r) + }) + } + } + } + + pub fn resolve_var(&self, rid: RegionVid) -> ty::Region { + match *self.values.borrow() { + None => { + self.tcx.sess.span_bug((*self.var_origins.borrow())[rid.index as usize].span(), + "attempt to resolve region variable before values have \ + been computed!") + } + Some(ref values) => { + let r = lookup(values, rid); + debug!("resolve_var({:?}) = {:?}", rid, r); + r + } + } + } + + pub fn opportunistic_resolve_var(&self, rid: RegionVid) -> ty::Region { + ty::ReVar(self.unification_table.borrow_mut().find_value(rid).min_vid) + } + + fn combine_map(&self, t: CombineMapType) -> &RefCell { + match t { + Glb => &self.glbs, + Lub => &self.lubs, + } + } + + pub fn combine_vars(&self, + t: CombineMapType, + a: Region, + b: Region, + origin: SubregionOrigin<'tcx>, + mut relate: F) + -> Region + where F: FnMut(&RegionVarBindings<'a, 'tcx>, Region, Region) + { + let vars = TwoRegions { a: a, b: b }; + match self.combine_map(t).borrow().get(&vars) { + Some(&c) => { + return ReVar(c); + } + None => {} + } + let c = self.new_region_var(MiscVariable(origin.span())); + self.combine_map(t).borrow_mut().insert(vars, c); + if self.in_snapshot() { + self.undo_log.borrow_mut().push(AddCombination(t, vars)); + } + relate(self, a, ReVar(c)); + relate(self, b, ReVar(c)); + debug!("combine_vars() c={:?}", c); + ReVar(c) + } + + pub fn vars_created_since_snapshot(&self, mark: &RegionSnapshot) -> Vec { + self.undo_log.borrow()[mark.length..] + .iter() + .filter_map(|&elt| { + match elt { + AddVar(vid) => Some(vid), + _ => None, + } + }) + .collect() + } + + /// Computes all regions that have been related to `r0` in any way since the mark `mark` was + /// made---`r0` itself will be the first entry. This is used when checking whether skolemized + /// regions are being improperly related to other regions. + pub fn tainted(&self, mark: &RegionSnapshot, r0: Region) -> Vec { + debug!("tainted(mark={:?}, r0={:?})", mark, r0); + let _indenter = indenter(); + + // `result_set` acts as a worklist: we explore all outgoing + // edges and add any new regions we find to result_set. This + // is not a terribly efficient implementation. + let mut result_set = vec![r0]; + let mut result_index = 0; + while result_index < result_set.len() { + // nb: can't use usize::range() here because result_set grows + let r = result_set[result_index]; + debug!("result_index={}, r={:?}", result_index, r); + + for undo_entry in self.undo_log.borrow()[mark.length..].iter() { + match undo_entry { + &AddConstraint(ConstrainVarSubVar(a, b)) => { + consider_adding_bidirectional_edges(&mut result_set, r, ReVar(a), ReVar(b)); + } + &AddConstraint(ConstrainRegSubVar(a, b)) => { + consider_adding_bidirectional_edges(&mut result_set, r, a, ReVar(b)); + } + &AddConstraint(ConstrainVarSubReg(a, b)) => { + consider_adding_bidirectional_edges(&mut result_set, r, ReVar(a), b); + } + &AddGiven(a, b) => { + consider_adding_bidirectional_edges(&mut result_set, + r, + ReFree(a), + ReVar(b)); + } + &AddVerify(i) => { + match (*self.verifys.borrow())[i] { + VerifyRegSubReg(_, a, b) => { + consider_adding_bidirectional_edges(&mut result_set, r, a, b); + } + VerifyGenericBound(_, _, a, ref bound) => { + bound.for_each_region(&mut |b| { + consider_adding_bidirectional_edges(&mut result_set, r, a, b) + }); + } + } + } + &AddCombination(..) | + &AddVar(..) | + &OpenSnapshot | + &CommitedSnapshot => {} + } + } + + result_index += 1; + } + + return result_set; + + fn consider_adding_bidirectional_edges(result_set: &mut Vec, + r: Region, + r1: Region, + r2: Region) { + consider_adding_directed_edge(result_set, r, r1, r2); + consider_adding_directed_edge(result_set, r, r2, r1); + } + + fn consider_adding_directed_edge(result_set: &mut Vec, + r: Region, + r1: Region, + r2: Region) { + if r == r1 { + // Clearly, this is potentially inefficient. + if !result_set.iter().any(|x| *x == r2) { + result_set.push(r2); + } + } + } + } + + /// This function performs the actual region resolution. It must be + /// called after all constraints have been added. It performs a + /// fixed-point iteration to find region values which satisfy all + /// constraints, assuming such values can be found; if they cannot, + /// errors are reported. + pub fn resolve_regions(&self, + free_regions: &FreeRegionMap, + subject_node: ast::NodeId) + -> Vec> { + debug!("RegionVarBindings: resolve_regions()"); + let mut errors = vec![]; + let v = self.infer_variable_values(free_regions, &mut errors, subject_node); + *self.values.borrow_mut() = Some(v); + errors + } + + fn lub_concrete_regions(&self, free_regions: &FreeRegionMap, a: Region, b: Region) -> Region { + match (a, b) { + (ReLateBound(..), _) | + (_, ReLateBound(..)) | + (ReEarlyBound(..), _) | + (_, ReEarlyBound(..)) => { + self.tcx.sess.bug(&format!("cannot relate bound region: LUB({:?}, {:?})", a, b)); + } + + (ReStatic, _) | (_, ReStatic) => { + ReStatic // nothing lives longer than static + } + + (ReEmpty, r) | (r, ReEmpty) => { + r // everything lives longer than empty + } + + (ReVar(v_id), _) | (_, ReVar(v_id)) => { + self.tcx.sess.span_bug((*self.var_origins.borrow())[v_id.index as usize].span(), + &format!("lub_concrete_regions invoked with non-concrete \ + regions: {:?}, {:?}", + a, + b)); + } + + (ReFree(ref fr), ReScope(s_id)) | + (ReScope(s_id), ReFree(ref fr)) => { + let f = ReFree(*fr); + // A "free" region can be interpreted as "some region + // at least as big as the block fr.scope_id". So, we can + // reasonably compare free regions and scopes: + let r_id = self.tcx.region_maps.nearest_common_ancestor(fr.scope, s_id); + + if r_id == fr.scope { + // if the free region's scope `fr.scope_id` is bigger than + // the scope region `s_id`, then the LUB is the free + // region itself: + f + } else { + // otherwise, we don't know what the free region is, + // so we must conservatively say the LUB is static: + ReStatic + } + } + + (ReScope(a_id), ReScope(b_id)) => { + // The region corresponding to an outer block is a + // subtype of the region corresponding to an inner + // block. + ReScope(self.tcx.region_maps.nearest_common_ancestor(a_id, b_id)) + } + + (ReFree(a_fr), ReFree(b_fr)) => { + free_regions.lub_free_regions(a_fr, b_fr) + } + + // For these types, we cannot define any additional + // relationship: + (ReSkolemized(..), _) | + (_, ReSkolemized(..)) => { + if a == b { + a + } else { + ReStatic + } + } + } + } +} + +// ______________________________________________________________________ + +#[derive(Copy, Clone, Debug)] +pub enum VarValue { + Value(Region), + ErrorValue, +} + +struct VarData { + value: VarValue, +} + +struct RegionAndOrigin<'tcx> { + region: Region, + origin: SubregionOrigin<'tcx>, +} + +type RegionGraph = graph::Graph<(), Constraint>; + +impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { + fn infer_variable_values(&self, + free_regions: &FreeRegionMap, + errors: &mut Vec>, + subject: ast::NodeId) + -> Vec { + let mut var_data = self.construct_var_data(); + + // Dorky hack to cause `dump_constraints` to only get called + // if debug mode is enabled: + debug!("----() End constraint listing (subject={}) {:?}---", + subject, + self.dump_constraints(subject)); + graphviz::maybe_print_constraints_for(self, subject); + + let graph = self.construct_graph(); + self.expand_givens(&graph); + self.expansion(free_regions, &mut var_data); + self.contraction(free_regions, &mut var_data); + let values = self.extract_values_and_collect_conflicts(free_regions, + &var_data, + &graph, + errors); + self.collect_concrete_region_errors(free_regions, &values, errors); + values + } + + fn construct_var_data(&self) -> Vec { + (0..self.num_vars() as usize) + .map(|_| VarData { value: Value(ty::ReEmpty) }) + .collect() + } + + fn dump_constraints(&self, subject: ast::NodeId) { + debug!("----() Start constraint listing (subject={}) ()----", + subject); + for (idx, (constraint, _)) in self.constraints.borrow().iter().enumerate() { + debug!("Constraint {} => {:?}", idx, constraint); + } + } + + fn expand_givens(&self, graph: &RegionGraph) { + // Givens are a kind of horrible hack to account for + // constraints like 'c <= '0 that are known to hold due to + // closure signatures (see the comment above on the `givens` + // field). They should go away. But until they do, the role + // of this fn is to account for the transitive nature: + // + // Given 'c <= '0 + // and '0 <= '1 + // then 'c <= '1 + + let mut givens = self.givens.borrow_mut(); + let seeds: Vec<_> = givens.iter().cloned().collect(); + for (fr, vid) in seeds { + let seed_index = NodeIndex(vid.index as usize); + for succ_index in graph.depth_traverse(seed_index) { + let succ_index = succ_index.0 as u32; + if succ_index < self.num_vars() { + let succ_vid = RegionVid { index: succ_index }; + givens.insert((fr, succ_vid)); + } + } + } + } + + fn expansion(&self, free_regions: &FreeRegionMap, var_data: &mut [VarData]) { + self.iterate_until_fixed_point("Expansion", |constraint| { + debug!("expansion: constraint={:?} origin={:?}", + constraint, + self.constraints + .borrow() + .get(constraint) + .unwrap()); + match *constraint { + ConstrainRegSubVar(a_region, b_vid) => { + let b_data = &mut var_data[b_vid.index as usize]; + self.expand_node(free_regions, a_region, b_vid, b_data) + } + ConstrainVarSubVar(a_vid, b_vid) => { + match var_data[a_vid.index as usize].value { + ErrorValue => false, + Value(a_region) => { + let b_node = &mut var_data[b_vid.index as usize]; + self.expand_node(free_regions, a_region, b_vid, b_node) + } + } + } + ConstrainVarSubReg(..) => { + // This is a contraction constraint. Ignore it. + false + } + } + }) + } + + fn expand_node(&self, + free_regions: &FreeRegionMap, + a_region: Region, + b_vid: RegionVid, + b_data: &mut VarData) + -> bool { + debug!("expand_node({:?}, {:?} == {:?})", + a_region, + b_vid, + b_data.value); + + // Check if this relationship is implied by a given. + match a_region { + ty::ReFree(fr) => { + if self.givens.borrow().contains(&(fr, b_vid)) { + debug!("given"); + return false; + } + } + _ => {} + } + + match b_data.value { + Value(cur_region) => { + let lub = self.lub_concrete_regions(free_regions, a_region, cur_region); + if lub == cur_region { + return false; + } + + debug!("Expanding value of {:?} from {:?} to {:?}", + b_vid, + cur_region, + lub); + + b_data.value = Value(lub); + return true; + } + + ErrorValue => { + return false; + } + } + } + + // FIXME(#29436) -- this fn would just go away if we removed ConstrainVarSubReg + fn contraction(&self, free_regions: &FreeRegionMap, var_data: &mut [VarData]) { + self.iterate_until_fixed_point("Contraction", |constraint| { + debug!("contraction: constraint={:?} origin={:?}", + constraint, + self.constraints + .borrow() + .get(constraint) + .unwrap()); + match *constraint { + ConstrainRegSubVar(..) | + ConstrainVarSubVar(..) => { + // Expansion will ensure that these constraints hold. Ignore. + } + ConstrainVarSubReg(a_vid, b_region) => { + let a_data = &mut var_data[a_vid.index as usize]; + debug!("contraction: {:?} == {:?}, {:?}", + a_vid, + a_data.value, + b_region); + + let a_region = match a_data.value { + ErrorValue => return false, + Value(a_region) => a_region, + }; + + if !free_regions.is_subregion_of(self.tcx, a_region, b_region) { + debug!("Setting {:?} to ErrorValue: {:?} not subregion of {:?}", + a_vid, + a_region, + b_region); + a_data.value = ErrorValue; + } + } + } + + false + }) + } + + fn collect_concrete_region_errors(&self, + free_regions: &FreeRegionMap, + values: &Vec, + errors: &mut Vec>) { + let mut reg_reg_dups = FnvHashSet(); + for verify in self.verifys.borrow().iter() { + match *verify { + VerifyRegSubReg(ref origin, sub, sup) => { + if free_regions.is_subregion_of(self.tcx, sub, sup) { + continue; + } + + if !reg_reg_dups.insert((sub, sup)) { + continue; + } + + debug!("region inference error at {:?}: {:?} <= {:?} is not true", + origin, + sub, + sup); + + errors.push(ConcreteFailure((*origin).clone(), sub, sup)); + } + + VerifyGenericBound(ref kind, ref origin, sub, ref bound) => { + let sub = normalize(values, sub); + if bound.is_met(self.tcx, free_regions, values, sub) { + continue; + } + + debug!("region inference error at {:?}: verifying {:?} <= {:?}", + origin, + sub, + bound); + + errors.push(GenericBoundFailure((*origin).clone(), kind.clone(), sub)); + } + } + } + } + + fn extract_values_and_collect_conflicts(&self, + free_regions: &FreeRegionMap, + var_data: &[VarData], + graph: &RegionGraph, + errors: &mut Vec>) + -> Vec { + debug!("extract_values_and_collect_conflicts()"); + + // This is the best way that I have found to suppress + // duplicate and related errors. Basically we keep a set of + // flags for every node. Whenever an error occurs, we will + // walk some portion of the graph looking to find pairs of + // conflicting regions to report to the user. As we walk, we + // trip the flags from false to true, and if we find that + // we've already reported an error involving any particular + // node we just stop and don't report the current error. The + // idea is to report errors that derive from independent + // regions of the graph, but not those that derive from + // overlapping locations. + let mut dup_vec = vec![u32::MAX; self.num_vars() as usize]; + + for idx in 0..self.num_vars() as usize { + match var_data[idx].value { + Value(_) => { + /* Inference successful */ + } + ErrorValue => { + /* Inference impossible, this value contains + inconsistent constraints. + + I think that in this case we should report an + error now---unlike the case above, we can't + wait to see whether the user needs the result + of this variable. The reason is that the mere + existence of this variable implies that the + region graph is inconsistent, whether or not it + is used. + + For example, we may have created a region + variable that is the GLB of two other regions + which do not have a GLB. Even if that variable + is not used, it implies that those two regions + *should* have a GLB. + + At least I think this is true. It may be that + the mere existence of a conflict in a region variable + that is not used is not a problem, so if this rule + starts to create problems we'll have to revisit + this portion of the code and think hard about it. =) */ + + let node_vid = RegionVid { index: idx as u32 }; + self.collect_error_for_expanding_node(free_regions, + graph, + &mut dup_vec, + node_vid, + errors); + } + } + } + + (0..self.num_vars() as usize).map(|idx| var_data[idx].value).collect() + } + + fn construct_graph(&self) -> RegionGraph { + let num_vars = self.num_vars(); + + let constraints = self.constraints.borrow(); + + let mut graph = graph::Graph::new(); + + for _ in 0..num_vars { + graph.add_node(()); + } + + // Issue #30438: two distinct dummy nodes, one for incoming + // edges (dummy_source) and another for outgoing edges + // (dummy_sink). In `dummy -> a -> b -> dummy`, using one + // dummy node leads one to think (erroneously) there exists a + // path from `b` to `a`. Two dummy nodes sidesteps the issue. + let dummy_source = graph.add_node(()); + let dummy_sink = graph.add_node(()); + + for (constraint, _) in constraints.iter() { + match *constraint { + ConstrainVarSubVar(a_id, b_id) => { + graph.add_edge(NodeIndex(a_id.index as usize), + NodeIndex(b_id.index as usize), + *constraint); + } + ConstrainRegSubVar(_, b_id) => { + graph.add_edge(dummy_source, NodeIndex(b_id.index as usize), *constraint); + } + ConstrainVarSubReg(a_id, _) => { + graph.add_edge(NodeIndex(a_id.index as usize), dummy_sink, *constraint); + } + } + } + + return graph; + } + + fn collect_error_for_expanding_node(&self, + free_regions: &FreeRegionMap, + graph: &RegionGraph, + dup_vec: &mut [u32], + node_idx: RegionVid, + errors: &mut Vec>) { + // Errors in expanding nodes result from a lower-bound that is + // not contained by an upper-bound. + let (mut lower_bounds, lower_dup) = self.collect_concrete_regions(graph, + node_idx, + graph::INCOMING, + dup_vec); + let (mut upper_bounds, upper_dup) = self.collect_concrete_regions(graph, + node_idx, + graph::OUTGOING, + dup_vec); + + if lower_dup || upper_dup { + return; + } + + // We place free regions first because we are special casing + // SubSupConflict(ReFree, ReFree) when reporting error, and so + // the user will more likely get a specific suggestion. + fn free_regions_first(a: &RegionAndOrigin, b: &RegionAndOrigin) -> Ordering { + match (a.region, b.region) { + (ReFree(..), ReFree(..)) => Equal, + (ReFree(..), _) => Less, + (_, ReFree(..)) => Greater, + (_, _) => Equal, + } + } + lower_bounds.sort_by(|a, b| free_regions_first(a, b)); + upper_bounds.sort_by(|a, b| free_regions_first(a, b)); + + for lower_bound in &lower_bounds { + for upper_bound in &upper_bounds { + if !free_regions.is_subregion_of(self.tcx, lower_bound.region, upper_bound.region) { + let origin = (*self.var_origins.borrow())[node_idx.index as usize].clone(); + debug!("region inference error at {:?} for {:?}: SubSupConflict sub: {:?} \ + sup: {:?}", + origin, + node_idx, + lower_bound.region, + upper_bound.region); + errors.push(SubSupConflict(origin, + lower_bound.origin.clone(), + lower_bound.region, + upper_bound.origin.clone(), + upper_bound.region)); + return; + } + } + } + + self.tcx.sess.span_bug((*self.var_origins.borrow())[node_idx.index as usize].span(), + &format!("collect_error_for_expanding_node() could not find \ + error for var {:?}, lower_bounds={:?}, \ + upper_bounds={:?}", + node_idx, + lower_bounds, + upper_bounds)); + } + + fn collect_concrete_regions(&self, + graph: &RegionGraph, + orig_node_idx: RegionVid, + dir: Direction, + dup_vec: &mut [u32]) + -> (Vec>, bool) { + struct WalkState<'tcx> { + set: FnvHashSet, + stack: Vec, + result: Vec>, + dup_found: bool, + } + let mut state = WalkState { + set: FnvHashSet(), + stack: vec![orig_node_idx], + result: Vec::new(), + dup_found: false, + }; + state.set.insert(orig_node_idx); + + // to start off the process, walk the source node in the + // direction specified + process_edges(self, &mut state, graph, orig_node_idx, dir); + + while !state.stack.is_empty() { + let node_idx = state.stack.pop().unwrap(); + + // check whether we've visited this node on some previous walk + if dup_vec[node_idx.index as usize] == u32::MAX { + dup_vec[node_idx.index as usize] = orig_node_idx.index; + } else if dup_vec[node_idx.index as usize] != orig_node_idx.index { + state.dup_found = true; + } + + debug!("collect_concrete_regions(orig_node_idx={:?}, node_idx={:?})", + orig_node_idx, + node_idx); + + // figure out the direction from which this node takes its + // values, and search for concrete regions etc in that direction + let dir = graph::INCOMING; + process_edges(self, &mut state, graph, node_idx, dir); + } + + let WalkState {result, dup_found, ..} = state; + return (result, dup_found); + + fn process_edges<'a, 'tcx>(this: &RegionVarBindings<'a, 'tcx>, + state: &mut WalkState<'tcx>, + graph: &RegionGraph, + source_vid: RegionVid, + dir: Direction) { + debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir); + + let source_node_index = NodeIndex(source_vid.index as usize); + for (_, edge) in graph.adjacent_edges(source_node_index, dir) { + match edge.data { + ConstrainVarSubVar(from_vid, to_vid) => { + let opp_vid = if from_vid == source_vid { + to_vid + } else { + from_vid + }; + if state.set.insert(opp_vid) { + state.stack.push(opp_vid); + } + } + + ConstrainRegSubVar(region, _) | + ConstrainVarSubReg(_, region) => { + state.result.push(RegionAndOrigin { + region: region, + origin: this.constraints.borrow().get(&edge.data).unwrap().clone(), + }); + } + } + } + } + } + + fn iterate_until_fixed_point(&self, tag: &str, mut body: F) + where F: FnMut(&Constraint) -> bool + { + let mut iteration = 0; + let mut changed = true; + while changed { + changed = false; + iteration += 1; + debug!("---- {} Iteration {}{}", "#", tag, iteration); + for (constraint, _) in self.constraints.borrow().iter() { + let edge_changed = body(constraint); + if edge_changed { + debug!("Updated due to constraint {:?}", constraint); + changed = true; + } + } + } + debug!("---- {} Complete after {} iteration(s)", tag, iteration); + } + +} + +impl<'tcx> fmt::Debug for Verify<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + VerifyRegSubReg(_, ref a, ref b) => { + write!(f, "VerifyRegSubReg({:?}, {:?})", a, b) + } + VerifyGenericBound(_, ref p, ref a, ref bs) => { + write!(f, "VerifyGenericBound({:?}, {:?}, {:?})", p, a, bs) + } + } + } +} + +fn normalize(values: &Vec, r: ty::Region) -> ty::Region { + match r { + ty::ReVar(rid) => lookup(values, rid), + _ => r, + } +} + +fn lookup(values: &Vec, rid: ty::RegionVid) -> ty::Region { + match values[rid.index as usize] { + Value(r) => r, + ErrorValue => ReStatic, // Previously reported error. + } +} + +impl<'tcx> fmt::Debug for RegionAndOrigin<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "RegionAndOrigin({:?},{:?})", self.region, self.origin) + } +} + +impl fmt::Debug for RegionSnapshot { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "RegionSnapshot(length={},skolemization={})", + self.length, self.skolemization_count) + } +} + +impl<'tcx> fmt::Debug for GenericKind<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + GenericKind::Param(ref p) => write!(f, "{:?}", p), + GenericKind::Projection(ref p) => write!(f, "{:?}", p), + } + } +} + +impl<'tcx> fmt::Display for GenericKind<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + GenericKind::Param(ref p) => write!(f, "{}", p), + GenericKind::Projection(ref p) => write!(f, "{}", p), + } + } +} + +impl<'tcx> GenericKind<'tcx> { + pub fn to_ty(&self, tcx: &TyCtxt<'tcx>) -> Ty<'tcx> { + match *self { + GenericKind::Param(ref p) => p.to_ty(tcx), + GenericKind::Projection(ref p) => tcx.mk_projection(p.trait_ref.clone(), p.item_name), + } + } +} + +impl VerifyBound { + fn for_each_region(&self, f: &mut FnMut(ty::Region)) { + match self { + &VerifyBound::AnyRegion(ref rs) | + &VerifyBound::AllRegions(ref rs) => for &r in rs { + f(r); + }, + + &VerifyBound::AnyBound(ref bs) | + &VerifyBound::AllBounds(ref bs) => for b in bs { + b.for_each_region(f); + }, + } + } + + pub fn must_hold(&self) -> bool { + match self { + &VerifyBound::AnyRegion(ref bs) => bs.contains(&ty::ReStatic), + &VerifyBound::AllRegions(ref bs) => bs.is_empty(), + &VerifyBound::AnyBound(ref bs) => bs.iter().any(|b| b.must_hold()), + &VerifyBound::AllBounds(ref bs) => bs.iter().all(|b| b.must_hold()), + } + } + + pub fn cannot_hold(&self) -> bool { + match self { + &VerifyBound::AnyRegion(ref bs) => bs.is_empty(), + &VerifyBound::AllRegions(ref bs) => bs.contains(&ty::ReEmpty), + &VerifyBound::AnyBound(ref bs) => bs.iter().all(|b| b.cannot_hold()), + &VerifyBound::AllBounds(ref bs) => bs.iter().any(|b| b.cannot_hold()), + } + } + + pub fn or(self, vb: VerifyBound) -> VerifyBound { + if self.must_hold() || vb.cannot_hold() { + self + } else if self.cannot_hold() || vb.must_hold() { + vb + } else { + VerifyBound::AnyBound(vec![self, vb]) + } + } + + pub fn and(self, vb: VerifyBound) -> VerifyBound { + if self.must_hold() && vb.must_hold() { + self + } else if self.cannot_hold() && vb.cannot_hold() { + self + } else { + VerifyBound::AllBounds(vec![self, vb]) + } + } + + fn is_met<'tcx>(&self, + tcx: &TyCtxt<'tcx>, + free_regions: &FreeRegionMap, + var_values: &Vec, + min: ty::Region) + -> bool { + match self { + &VerifyBound::AnyRegion(ref rs) => + rs.iter() + .map(|&r| normalize(var_values, r)) + .any(|r| free_regions.is_subregion_of(tcx, min, r)), + + &VerifyBound::AllRegions(ref rs) => + rs.iter() + .map(|&r| normalize(var_values, r)) + .all(|r| free_regions.is_subregion_of(tcx, min, r)), + + &VerifyBound::AnyBound(ref bs) => + bs.iter() + .any(|b| b.is_met(tcx, free_regions, var_values, min)), + + &VerifyBound::AllBounds(ref bs) => + bs.iter() + .all(|b| b.is_met(tcx, free_regions, var_values, min)), + } + } +} diff --git a/src/librustc/infer/resolve.rs b/src/librustc/infer/resolve.rs new file mode 100644 index 00000000000..c54843410ad --- /dev/null +++ b/src/librustc/infer/resolve.rs @@ -0,0 +1,147 @@ +// Copyright 2012 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::{InferCtxt, FixupError, FixupResult}; +use ty::{self, Ty, TyCtxt, TypeFoldable}; + +/////////////////////////////////////////////////////////////////////////// +// OPPORTUNISTIC TYPE RESOLVER + +/// The opportunistic type resolver can be used at any time. It simply replaces +/// type variables that have been unified with the things they have +/// been unified with (similar to `shallow_resolve`, but deep). This is +/// useful for printing messages etc but also required at various +/// points for correctness. +pub struct OpportunisticTypeResolver<'a, 'tcx:'a> { + infcx: &'a InferCtxt<'a, 'tcx>, +} + +impl<'a, 'tcx> OpportunisticTypeResolver<'a, 'tcx> { + pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> OpportunisticTypeResolver<'a, 'tcx> { + OpportunisticTypeResolver { infcx: infcx } + } +} + +impl<'a, 'tcx> ty::fold::TypeFolder<'tcx> for OpportunisticTypeResolver<'a, 'tcx> { + fn tcx(&self) -> &TyCtxt<'tcx> { + self.infcx.tcx + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + if !t.has_infer_types() { + t // micro-optimize -- if there is nothing in this type that this fold affects... + } else { + let t0 = self.infcx.shallow_resolve(t); + t0.super_fold_with(self) + } + } +} + +/// The opportunistic type and region resolver is similar to the +/// opportunistic type resolver, but also opportunistly resolves +/// regions. It is useful for canonicalization. +pub struct OpportunisticTypeAndRegionResolver<'a, 'tcx:'a> { + infcx: &'a InferCtxt<'a, 'tcx>, +} + +impl<'a, 'tcx> OpportunisticTypeAndRegionResolver<'a, 'tcx> { + pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self { + OpportunisticTypeAndRegionResolver { infcx: infcx } + } +} + +impl<'a, 'tcx> ty::fold::TypeFolder<'tcx> for OpportunisticTypeAndRegionResolver<'a, 'tcx> { + fn tcx(&self) -> &TyCtxt<'tcx> { + self.infcx.tcx + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + if !t.needs_infer() { + t // micro-optimize -- if there is nothing in this type that this fold affects... + } else { + let t0 = self.infcx.shallow_resolve(t); + t0.super_fold_with(self) + } + } + + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + match r { + ty::ReVar(rid) => self.infcx.region_vars.opportunistic_resolve_var(rid), + _ => r, + } + } +} + +/////////////////////////////////////////////////////////////////////////// +// FULL TYPE RESOLUTION + +/// Full type resolution replaces all type and region variables with +/// their concrete results. If any variable cannot be replaced (never unified, etc) +/// then an `Err` result is returned. +pub fn fully_resolve<'a, 'tcx, T>(infcx: &InferCtxt<'a,'tcx>, value: &T) -> FixupResult + where T : TypeFoldable<'tcx> +{ + let mut full_resolver = FullTypeResolver { infcx: infcx, err: None }; + let result = value.fold_with(&mut full_resolver); + match full_resolver.err { + None => Ok(result), + Some(e) => Err(e), + } +} + +// N.B. This type is not public because the protocol around checking the +// `err` field is not enforcable otherwise. +struct FullTypeResolver<'a, 'tcx:'a> { + infcx: &'a InferCtxt<'a, 'tcx>, + err: Option, +} + +impl<'a, 'tcx> ty::fold::TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { + fn tcx(&self) -> &TyCtxt<'tcx> { + self.infcx.tcx + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + if !t.needs_infer() { + t // micro-optimize -- if there is nothing in this type that this fold affects... + } else { + let t = self.infcx.shallow_resolve(t); + match t.sty { + ty::TyInfer(ty::TyVar(vid)) => { + self.err = Some(FixupError::UnresolvedTy(vid)); + self.tcx().types.err + } + ty::TyInfer(ty::IntVar(vid)) => { + self.err = Some(FixupError::UnresolvedIntTy(vid)); + self.tcx().types.err + } + ty::TyInfer(ty::FloatVar(vid)) => { + self.err = Some(FixupError::UnresolvedFloatTy(vid)); + self.tcx().types.err + } + ty::TyInfer(_) => { + self.infcx.tcx.sess.bug( + &format!("Unexpected type in full type resolver: {:?}", + t)); + } + _ => { + t.super_fold_with(self) + } + } + } + } + + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + match r { + ty::ReVar(rid) => self.infcx.region_vars.resolve_var(rid), + _ => r, + } + } +} diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs new file mode 100644 index 00000000000..0505c9d627b --- /dev/null +++ b/src/librustc/infer/sub.rs @@ -0,0 +1,116 @@ +// Copyright 2012 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::combine::{self, CombineFields}; +use super::higher_ranked::HigherRankedRelations; +use super::SubregionOrigin; +use super::type_variable::{SubtypeOf, SupertypeOf}; + +use ty::{self, Ty, TyCtxt}; +use ty::TyVar; +use ty::relate::{Cause, Relate, RelateResult, TypeRelation}; +use std::mem; + +/// Ensures `a` is made a subtype of `b`. Returns `a` on success. +pub struct Sub<'a, 'tcx: 'a> { + fields: CombineFields<'a, 'tcx>, +} + +impl<'a, 'tcx> Sub<'a, 'tcx> { + pub fn new(f: CombineFields<'a, 'tcx>) -> Sub<'a, 'tcx> { + Sub { fields: f } + } +} + +impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Sub<'a, 'tcx> { + fn tag(&self) -> &'static str { "Sub" } + fn tcx(&self) -> &'a TyCtxt<'tcx> { self.fields.infcx.tcx } + fn a_is_expected(&self) -> bool { self.fields.a_is_expected } + + fn with_cause(&mut self, cause: Cause, f: F) -> R + where F: FnOnce(&mut Self) -> R + { + debug!("sub with_cause={:?}", cause); + let old_cause = mem::replace(&mut self.fields.cause, Some(cause)); + let r = f(self); + debug!("sub old_cause={:?}", old_cause); + self.fields.cause = old_cause; + r + } + + fn relate_with_variance>(&mut self, + variance: ty::Variance, + a: &T, + b: &T) + -> RelateResult<'tcx, T> + { + match variance { + ty::Invariant => self.fields.equate().relate(a, b), + ty::Covariant => self.relate(a, b), + ty::Bivariant => self.fields.bivariate().relate(a, b), + ty::Contravariant => self.fields.switch_expected().sub().relate(b, a), + } + } + + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + debug!("{}.tys({:?}, {:?})", self.tag(), a, b); + + if a == b { return Ok(a); } + + let infcx = self.fields.infcx; + let a = infcx.type_variables.borrow_mut().replace_if_possible(a); + let b = infcx.type_variables.borrow_mut().replace_if_possible(b); + match (&a.sty, &b.sty) { + (&ty::TyInfer(TyVar(a_id)), &ty::TyInfer(TyVar(b_id))) => { + infcx.type_variables + .borrow_mut() + .relate_vars(a_id, SubtypeOf, b_id); + Ok(a) + } + (&ty::TyInfer(TyVar(a_id)), _) => { + self.fields + .switch_expected() + .instantiate(b, SupertypeOf, a_id)?; + Ok(a) + } + (_, &ty::TyInfer(TyVar(b_id))) => { + self.fields.instantiate(a, SubtypeOf, b_id)?; + Ok(a) + } + + (&ty::TyError, _) | (_, &ty::TyError) => { + Ok(self.tcx().types.err) + } + + _ => { + combine::super_combine_tys(self.fields.infcx, self, a, b)?; + Ok(a) + } + } + } + + fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> { + debug!("{}.regions({:?}, {:?}) self.cause={:?}", + self.tag(), a, b, self.fields.cause); + // FIXME -- we have more fine-grained information available + // from the "cause" field, we could perhaps give more tailored + // error messages. + let origin = SubregionOrigin::Subtype(self.fields.trace.clone()); + self.fields.infcx.region_vars.make_subregion(origin, a, b); + Ok(a) + } + + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where T: Relate<'a,'tcx> + { + self.fields.higher_ranked_sub(a, b) + } +} diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs new file mode 100644 index 00000000000..c8da346085d --- /dev/null +++ b/src/librustc/infer/type_variable.rs @@ -0,0 +1,324 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use self::RelationDir::*; +use self::TypeVariableValue::*; +use self::UndoEntry::*; +use middle::def_id::{DefId}; +use ty::{self, Ty}; +use syntax::codemap::Span; + +use std::cmp::min; +use std::marker::PhantomData; +use std::mem; +use std::u32; +use rustc_data_structures::snapshot_vec as sv; +use rustc_data_structures::unify as ut; + +pub struct TypeVariableTable<'tcx> { + values: sv::SnapshotVec>, + eq_relations: ut::UnificationTable, +} + +struct TypeVariableData<'tcx> { + value: TypeVariableValue<'tcx>, + diverging: bool +} + +enum TypeVariableValue<'tcx> { + Known(Ty<'tcx>), + Bounded { + relations: Vec, + default: Option> + } +} + +// We will use this to store the required information to recapitulate what happened when +// an error occurs. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct Default<'tcx> { + pub ty: Ty<'tcx>, + /// The span where the default was incurred + pub origin_span: Span, + /// The definition that the default originates from + pub def_id: DefId +} + +pub struct Snapshot { + snapshot: sv::Snapshot, + eq_snapshot: ut::Snapshot, +} + +enum UndoEntry<'tcx> { + // The type of the var was specified. + SpecifyVar(ty::TyVid, Vec, Option>), + Relate(ty::TyVid, ty::TyVid), + RelateRange(ty::TyVid, usize), +} + +struct Delegate<'tcx>(PhantomData<&'tcx ()>); + +type Relation = (RelationDir, ty::TyVid); + +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub enum RelationDir { + SubtypeOf, SupertypeOf, EqTo, BiTo +} + +impl RelationDir { + fn opposite(self) -> RelationDir { + match self { + SubtypeOf => SupertypeOf, + SupertypeOf => SubtypeOf, + EqTo => EqTo, + BiTo => BiTo, + } + } +} + +impl<'tcx> TypeVariableTable<'tcx> { + pub fn new() -> TypeVariableTable<'tcx> { + TypeVariableTable { + values: sv::SnapshotVec::new(), + eq_relations: ut::UnificationTable::new(), + } + } + + fn relations<'a>(&'a mut self, a: ty::TyVid) -> &'a mut Vec { + relations(self.values.get_mut(a.index as usize)) + } + + pub fn default(&self, vid: ty::TyVid) -> Option> { + match &self.values.get(vid.index as usize).value { + &Known(_) => None, + &Bounded { ref default, .. } => default.clone() + } + } + + pub fn var_diverges<'a>(&'a self, vid: ty::TyVid) -> bool { + self.values.get(vid.index as usize).diverging + } + + /// Records that `a <: b`, `a :> b`, or `a == b`, depending on `dir`. + /// + /// Precondition: neither `a` nor `b` are known. + pub fn relate_vars(&mut self, a: ty::TyVid, dir: RelationDir, b: ty::TyVid) { + let a = self.root_var(a); + let b = self.root_var(b); + if a != b { + if dir == EqTo { + // a and b must be equal which we mark in the unification table + let root = self.eq_relations.union(a, b); + // In addition to being equal, all relations from the variable which is no longer + // the root must be added to the root so they are not forgotten as the other + // variable should no longer be referenced (other than to get the root) + let other = if a == root { b } else { a }; + let count = { + let (relations, root_relations) = if other.index < root.index { + let (pre, post) = self.values.split_at_mut(root.index as usize); + (relations(&mut pre[other.index as usize]), relations(&mut post[0])) + } else { + let (pre, post) = self.values.split_at_mut(other.index as usize); + (relations(&mut post[0]), relations(&mut pre[root.index as usize])) + }; + root_relations.extend_from_slice(relations); + relations.len() + }; + self.values.record(RelateRange(root, count)); + } else { + self.relations(a).push((dir, b)); + self.relations(b).push((dir.opposite(), a)); + self.values.record(Relate(a, b)); + } + } + } + + /// Instantiates `vid` with the type `ty` and then pushes an entry onto `stack` for each of the + /// relations of `vid` to other variables. The relations will have the form `(ty, dir, vid1)` + /// where `vid1` is some other variable id. + /// + /// Precondition: `vid` must be a root in the unification table + pub fn instantiate_and_push( + &mut self, + vid: ty::TyVid, + ty: Ty<'tcx>, + stack: &mut Vec<(Ty<'tcx>, RelationDir, ty::TyVid)>) + { + debug_assert!(self.root_var(vid) == vid); + let old_value = { + let value_ptr = &mut self.values.get_mut(vid.index as usize).value; + mem::replace(value_ptr, Known(ty)) + }; + + let (relations, default) = match old_value { + Bounded { relations, default } => (relations, default), + Known(_) => panic!("Asked to instantiate variable that is \ + already instantiated") + }; + + for &(dir, vid) in &relations { + stack.push((ty, dir, vid)); + } + + self.values.record(SpecifyVar(vid, relations, default)); + } + + pub fn new_var(&mut self, + diverging: bool, + default: Option>) -> ty::TyVid { + self.eq_relations.new_key(()); + let index = self.values.push(TypeVariableData { + value: Bounded { relations: vec![], default: default }, + diverging: diverging + }); + ty::TyVid { index: index as u32 } + } + + pub fn root_var(&mut self, vid: ty::TyVid) -> ty::TyVid { + self.eq_relations.find(vid) + } + + pub fn probe(&mut self, vid: ty::TyVid) -> Option> { + let vid = self.root_var(vid); + self.probe_root(vid) + } + + /// Retrieves the type of `vid` given that it is currently a root in the unification table + pub fn probe_root(&mut self, vid: ty::TyVid) -> Option> { + debug_assert!(self.root_var(vid) == vid); + match self.values.get(vid.index as usize).value { + Bounded { .. } => None, + Known(t) => Some(t) + } + } + + pub fn replace_if_possible(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + match t.sty { + ty::TyInfer(ty::TyVar(v)) => { + match self.probe(v) { + None => t, + Some(u) => u + } + } + _ => t, + } + } + + pub fn snapshot(&mut self) -> Snapshot { + Snapshot { + snapshot: self.values.start_snapshot(), + eq_snapshot: self.eq_relations.snapshot(), + } + } + + pub fn rollback_to(&mut self, s: Snapshot) { + self.values.rollback_to(s.snapshot); + self.eq_relations.rollback_to(s.eq_snapshot); + } + + pub fn commit(&mut self, s: Snapshot) { + self.values.commit(s.snapshot); + self.eq_relations.commit(s.eq_snapshot); + } + + pub fn types_escaping_snapshot(&mut self, s: &Snapshot) -> Vec> { + /*! + * Find the set of type variables that existed *before* `s` + * but which have only been unified since `s` started, and + * return the types with which they were unified. So if we had + * a type variable `V0`, then we started the snapshot, then we + * created a type variable `V1`, unifed `V0` with `T0`, and + * unified `V1` with `T1`, this function would return `{T0}`. + */ + + let mut new_elem_threshold = u32::MAX; + let mut escaping_types = Vec::new(); + let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot); + debug!("actions_since_snapshot.len() = {}", actions_since_snapshot.len()); + for action in actions_since_snapshot { + match *action { + sv::UndoLog::NewElem(index) => { + // if any new variables were created during the + // snapshot, remember the lower index (which will + // always be the first one we see). Note that this + // action must precede those variables being + // specified. + new_elem_threshold = min(new_elem_threshold, index as u32); + debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold); + } + + sv::UndoLog::Other(SpecifyVar(vid, _, _)) => { + if vid.index < new_elem_threshold { + // quick check to see if this variable was + // created since the snapshot started or not. + let escaping_type = match self.values.get(vid.index as usize).value { + Bounded { .. } => unreachable!(), + Known(ty) => ty, + }; + escaping_types.push(escaping_type); + } + debug!("SpecifyVar({:?}) new_elem_threshold={}", vid, new_elem_threshold); + } + + _ => { } + } + } + + escaping_types + } + + pub fn unsolved_variables(&mut self) -> Vec { + (0..self.values.len()) + .filter_map(|i| { + let vid = ty::TyVid { index: i as u32 }; + if self.probe(vid).is_some() { + None + } else { + Some(vid) + } + }) + .collect() + } +} + +impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> { + type Value = TypeVariableData<'tcx>; + type Undo = UndoEntry<'tcx>; + + fn reverse(values: &mut Vec>, action: UndoEntry<'tcx>) { + match action { + SpecifyVar(vid, relations, default) => { + values[vid.index as usize].value = Bounded { + relations: relations, + default: default + }; + } + + Relate(a, b) => { + relations(&mut (*values)[a.index as usize]).pop(); + relations(&mut (*values)[b.index as usize]).pop(); + } + + RelateRange(i, n) => { + let relations = relations(&mut (*values)[i.index as usize]); + for _ in 0..n { + relations.pop(); + } + } + } + } +} + +fn relations<'a>(v: &'a mut TypeVariableData) -> &'a mut Vec { + match v.value { + Known(_) => panic!("var_sub_var: variable is known"), + Bounded { ref mut relations, .. } => relations + } +} diff --git a/src/librustc/infer/unify_key.rs b/src/librustc/infer/unify_key.rs new file mode 100644 index 00000000000..a9eb20b8299 --- /dev/null +++ b/src/librustc/infer/unify_key.rs @@ -0,0 +1,82 @@ +// Copyright 2012-2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::ast; +use ty::{self, IntVarValue, Ty, TyCtxt}; +use rustc_data_structures::unify::{Combine, UnifyKey}; + +pub trait ToType<'tcx> { + fn to_type(&self, tcx: &TyCtxt<'tcx>) -> Ty<'tcx>; +} + +impl UnifyKey for ty::IntVid { + type Value = Option; + fn index(&self) -> u32 { self.index } + fn from_index(i: u32) -> ty::IntVid { ty::IntVid { index: i } } + fn tag(_: Option) -> &'static str { "IntVid" } +} + +#[derive(PartialEq, Copy, Clone, Debug)] +pub struct RegionVidKey { + /// The minimum region vid in the unification set. This is needed + /// to have a canonical name for a type to prevent infinite + /// recursion. + pub min_vid: ty::RegionVid +} + +impl Combine for RegionVidKey { + fn combine(&self, other: &RegionVidKey) -> RegionVidKey { + let min_vid = if self.min_vid.index < other.min_vid.index { + self.min_vid + } else { + other.min_vid + }; + + RegionVidKey { min_vid: min_vid } + } +} + +impl UnifyKey for ty::RegionVid { + type Value = RegionVidKey; + fn index(&self) -> u32 { self.index } + fn from_index(i: u32) -> ty::RegionVid { ty::RegionVid { index: i } } + fn tag(_: Option) -> &'static str { "RegionVid" } +} + +impl<'tcx> ToType<'tcx> for IntVarValue { + fn to_type(&self, tcx: &TyCtxt<'tcx>) -> Ty<'tcx> { + match *self { + ty::IntType(i) => tcx.mk_mach_int(i), + ty::UintType(i) => tcx.mk_mach_uint(i), + } + } +} + +// Floating point type keys + +impl UnifyKey for ty::FloatVid { + type Value = Option; + fn index(&self) -> u32 { self.index } + fn from_index(i: u32) -> ty::FloatVid { ty::FloatVid { index: i } } + fn tag(_: Option) -> &'static str { "FloatVid" } +} + +impl<'tcx> ToType<'tcx> for ast::FloatTy { + fn to_type(&self, tcx: &TyCtxt<'tcx>) -> Ty<'tcx> { + tcx.mk_mach_float(*self) + } +} + +impl UnifyKey for ty::TyVid { + type Value = (); + fn index(&self) -> u32 { self.index } + fn from_index(i: u32) -> ty::TyVid { ty::TyVid { index: i } } + fn tag(_: Option) -> &'static str { "TyVid" } +} diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 37b6ea7872a..4fdfe59e2b0 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -78,6 +78,7 @@ pub mod back { pub use rustc_back::svh; } +pub mod cfg; pub mod dep_graph; pub mod front { @@ -85,10 +86,12 @@ pub mod front { pub mod map; } +pub mod infer; +pub mod lint; + pub mod middle { pub mod astconv_util; pub mod expr_use_visitor; // STAGE0: increase glitch immunity - pub mod cfg; pub mod check_match; pub mod const_eval; pub mod const_qualif; @@ -102,7 +105,6 @@ pub mod middle { pub mod entry; pub mod free_region; pub mod intrinsicck; - pub mod infer; pub mod lang_items; pub mod liveness; pub mod mem_categorization; @@ -113,8 +115,6 @@ pub mod middle { pub mod recursion_limit; pub mod resolve_lifetime; pub mod stability; - pub mod traits; - pub mod ty; pub mod weak_lang_items; } @@ -127,8 +127,8 @@ pub mod mir { } pub mod session; - -pub mod lint; +pub mod traits; +pub mod ty; pub mod util { pub use rustc_back::sha2; diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 079a0c94cc5..8224422d45c 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -27,7 +27,7 @@ use self::TargetLint::*; use dep_graph::DepNode; use middle::privacy::AccessLevels; -use middle::ty::TyCtxt; +use ty::TyCtxt; use session::{config, early_error, Session}; use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass}; use lint::{EarlyLintPass, EarlyLintPassObject, LateLintPass, LateLintPassObject}; diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs index e17aaaca16e..a6907aad297 100644 --- a/src/librustc/middle/astconv_util.rs +++ b/src/librustc/middle/astconv_util.rs @@ -15,7 +15,7 @@ */ use middle::def::Def; -use middle::ty::{Ty, TyCtxt}; +use ty::{Ty, TyCtxt}; use syntax::codemap::Span; use rustc_front::hir as ast; diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs deleted file mode 100644 index dcfa8d1e36a..00000000000 --- a/src/librustc/middle/cfg/construct.rs +++ /dev/null @@ -1,596 +0,0 @@ -// Copyright 2012-2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use rustc_data_structures::graph; -use middle::cfg::*; -use middle::def::Def; -use middle::pat_util; -use middle::ty::{self, TyCtxt}; -use syntax::ast; -use syntax::ptr::P; - -use rustc_front::hir::{self, PatKind}; - -struct CFGBuilder<'a, 'tcx: 'a> { - tcx: &'a TyCtxt<'tcx>, - graph: CFGGraph, - fn_exit: CFGIndex, - loop_scopes: Vec, -} - -#[derive(Copy, Clone)] -struct LoopScope { - loop_id: ast::NodeId, // id of loop/while node - continue_index: CFGIndex, // where to go on a `loop` - break_index: CFGIndex, // where to go on a `break -} - -pub fn construct(tcx: &TyCtxt, - blk: &hir::Block) -> CFG { - let mut graph = graph::Graph::new(); - let entry = graph.add_node(CFGNodeData::Entry); - - // `fn_exit` is target of return exprs, which lies somewhere - // outside input `blk`. (Distinguishing `fn_exit` and `block_exit` - // also resolves chicken-and-egg problem that arises if you try to - // have return exprs jump to `block_exit` during construction.) - let fn_exit = graph.add_node(CFGNodeData::Exit); - let block_exit; - - let mut cfg_builder = CFGBuilder { - graph: graph, - fn_exit: fn_exit, - tcx: tcx, - loop_scopes: Vec::new() - }; - block_exit = cfg_builder.block(blk, entry); - cfg_builder.add_contained_edge(block_exit, fn_exit); - let CFGBuilder {graph, ..} = cfg_builder; - CFG {graph: graph, - entry: entry, - exit: fn_exit} -} - -impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { - fn block(&mut self, blk: &hir::Block, pred: CFGIndex) -> CFGIndex { - let mut stmts_exit = pred; - for stmt in &blk.stmts { - stmts_exit = self.stmt(stmt, stmts_exit); - } - - let expr_exit = self.opt_expr(&blk.expr, stmts_exit); - - self.add_ast_node(blk.id, &[expr_exit]) - } - - fn stmt(&mut self, stmt: &hir::Stmt, pred: CFGIndex) -> CFGIndex { - match stmt.node { - hir::StmtDecl(ref decl, id) => { - let exit = self.decl(&decl, pred); - self.add_ast_node(id, &[exit]) - } - - hir::StmtExpr(ref expr, id) | hir::StmtSemi(ref expr, id) => { - let exit = self.expr(&expr, pred); - self.add_ast_node(id, &[exit]) - } - } - } - - fn decl(&mut self, decl: &hir::Decl, pred: CFGIndex) -> CFGIndex { - match decl.node { - hir::DeclLocal(ref local) => { - let init_exit = self.opt_expr(&local.init, pred); - self.pat(&local.pat, init_exit) - } - - hir::DeclItem(_) => { - pred - } - } - } - - fn pat(&mut self, pat: &hir::Pat, pred: CFGIndex) -> CFGIndex { - match pat.node { - PatKind::Ident(_, _, None) | - PatKind::TupleStruct(_, None) | - PatKind::Path(..) | - PatKind::QPath(..) | - PatKind::Lit(..) | - PatKind::Range(..) | - PatKind::Wild => { - self.add_ast_node(pat.id, &[pred]) - } - - PatKind::Box(ref subpat) | - PatKind::Ref(ref subpat, _) | - PatKind::Ident(_, _, Some(ref subpat)) => { - let subpat_exit = self.pat(&subpat, pred); - self.add_ast_node(pat.id, &[subpat_exit]) - } - - PatKind::TupleStruct(_, Some(ref subpats)) | - PatKind::Tup(ref subpats) => { - let pats_exit = self.pats_all(subpats.iter(), pred); - self.add_ast_node(pat.id, &[pats_exit]) - } - - PatKind::Struct(_, ref subpats, _) => { - let pats_exit = - self.pats_all(subpats.iter().map(|f| &f.node.pat), pred); - self.add_ast_node(pat.id, &[pats_exit]) - } - - PatKind::Vec(ref pre, ref vec, ref post) => { - let pre_exit = self.pats_all(pre.iter(), pred); - let vec_exit = self.pats_all(vec.iter(), pre_exit); - let post_exit = self.pats_all(post.iter(), vec_exit); - self.add_ast_node(pat.id, &[post_exit]) - } - } - } - - fn pats_all<'b, I: Iterator>>(&mut self, - pats: I, - pred: CFGIndex) -> CFGIndex { - //! Handles case where all of the patterns must match. - pats.fold(pred, |pred, pat| self.pat(&pat, pred)) - } - - fn expr(&mut self, expr: &hir::Expr, pred: CFGIndex) -> CFGIndex { - match expr.node { - hir::ExprBlock(ref blk) => { - let blk_exit = self.block(&blk, pred); - self.add_ast_node(expr.id, &[blk_exit]) - } - - hir::ExprIf(ref cond, ref then, None) => { - // - // [pred] - // | - // v 1 - // [cond] - // | - // / \ - // / \ - // v 2 * - // [then] | - // | | - // v 3 v 4 - // [..expr..] - // - let cond_exit = self.expr(&cond, pred); // 1 - let then_exit = self.block(&then, cond_exit); // 2 - self.add_ast_node(expr.id, &[cond_exit, then_exit]) // 3,4 - } - - hir::ExprIf(ref cond, ref then, Some(ref otherwise)) => { - // - // [pred] - // | - // v 1 - // [cond] - // | - // / \ - // / \ - // v 2 v 3 - // [then][otherwise] - // | | - // v 4 v 5 - // [..expr..] - // - let cond_exit = self.expr(&cond, pred); // 1 - let then_exit = self.block(&then, cond_exit); // 2 - let else_exit = self.expr(&otherwise, cond_exit); // 3 - self.add_ast_node(expr.id, &[then_exit, else_exit]) // 4, 5 - } - - hir::ExprWhile(ref cond, ref body, _) => { - // - // [pred] - // | - // v 1 - // [loopback] <--+ 5 - // | | - // v 2 | - // +-----[cond] | - // | | | - // | v 4 | - // | [body] -----+ - // v 3 - // [expr] - // - // Note that `break` and `continue` statements - // may cause additional edges. - - // Is the condition considered part of the loop? - let loopback = self.add_dummy_node(&[pred]); // 1 - let cond_exit = self.expr(&cond, loopback); // 2 - let expr_exit = self.add_ast_node(expr.id, &[cond_exit]); // 3 - self.loop_scopes.push(LoopScope { - loop_id: expr.id, - continue_index: loopback, - break_index: expr_exit - }); - let body_exit = self.block(&body, cond_exit); // 4 - self.add_contained_edge(body_exit, loopback); // 5 - self.loop_scopes.pop(); - expr_exit - } - - hir::ExprLoop(ref body, _) => { - // - // [pred] - // | - // v 1 - // [loopback] <---+ - // | 4 | - // v 3 | - // [body] ------+ - // - // [expr] 2 - // - // Note that `break` and `loop` statements - // may cause additional edges. - - let loopback = self.add_dummy_node(&[pred]); // 1 - let expr_exit = self.add_ast_node(expr.id, &[]); // 2 - self.loop_scopes.push(LoopScope { - loop_id: expr.id, - continue_index: loopback, - break_index: expr_exit, - }); - let body_exit = self.block(&body, loopback); // 3 - self.add_contained_edge(body_exit, loopback); // 4 - self.loop_scopes.pop(); - expr_exit - } - - hir::ExprMatch(ref discr, ref arms, _) => { - self.match_(expr.id, &discr, &arms, pred) - } - - hir::ExprBinary(op, ref l, ref r) if ::rustc_front::util::lazy_binop(op.node) => { - // - // [pred] - // | - // v 1 - // [l] - // | - // / \ - // / \ - // v 2 * - // [r] | - // | | - // v 3 v 4 - // [..exit..] - // - let l_exit = self.expr(&l, pred); // 1 - let r_exit = self.expr(&r, l_exit); // 2 - self.add_ast_node(expr.id, &[l_exit, r_exit]) // 3,4 - } - - hir::ExprRet(ref v) => { - let v_exit = self.opt_expr(v, pred); - let b = self.add_ast_node(expr.id, &[v_exit]); - self.add_returning_edge(expr, b); - self.add_unreachable_node() - } - - hir::ExprBreak(label) => { - let loop_scope = self.find_scope(expr, label.map(|l| l.node.name)); - let b = self.add_ast_node(expr.id, &[pred]); - self.add_exiting_edge(expr, b, - loop_scope, loop_scope.break_index); - self.add_unreachable_node() - } - - hir::ExprAgain(label) => { - let loop_scope = self.find_scope(expr, label.map(|l| l.node.name)); - let a = self.add_ast_node(expr.id, &[pred]); - self.add_exiting_edge(expr, a, - loop_scope, loop_scope.continue_index); - self.add_unreachable_node() - } - - hir::ExprVec(ref elems) => { - self.straightline(expr, pred, elems.iter().map(|e| &**e)) - } - - hir::ExprCall(ref func, ref args) => { - self.call(expr, pred, &func, args.iter().map(|e| &**e)) - } - - hir::ExprMethodCall(_, _, ref args) => { - self.call(expr, pred, &args[0], args[1..].iter().map(|e| &**e)) - } - - hir::ExprIndex(ref l, ref r) | - hir::ExprBinary(_, ref l, ref r) if self.tcx.is_method_call(expr.id) => { - self.call(expr, pred, &l, Some(&**r).into_iter()) - } - - hir::ExprUnary(_, ref e) if self.tcx.is_method_call(expr.id) => { - self.call(expr, pred, &e, None::.iter()) - } - - hir::ExprTup(ref exprs) => { - self.straightline(expr, pred, exprs.iter().map(|e| &**e)) - } - - hir::ExprStruct(_, ref fields, ref base) => { - let field_cfg = self.straightline(expr, pred, fields.iter().map(|f| &*f.expr)); - self.opt_expr(base, field_cfg) - } - - hir::ExprRepeat(ref elem, ref count) => { - self.straightline(expr, pred, [elem, count].iter().map(|&e| &**e)) - } - - hir::ExprAssign(ref l, ref r) | - hir::ExprAssignOp(_, ref l, ref r) => { - self.straightline(expr, pred, [r, l].iter().map(|&e| &**e)) - } - - hir::ExprIndex(ref l, ref r) | - hir::ExprBinary(_, ref l, ref r) => { // NB: && and || handled earlier - self.straightline(expr, pred, [l, r].iter().map(|&e| &**e)) - } - - hir::ExprBox(ref e) | - hir::ExprAddrOf(_, ref e) | - hir::ExprCast(ref e, _) | - hir::ExprType(ref e, _) | - hir::ExprUnary(_, ref e) | - hir::ExprField(ref e, _) | - hir::ExprTupField(ref e, _) => { - self.straightline(expr, pred, Some(&**e).into_iter()) - } - - hir::ExprInlineAsm(_, ref outputs, ref inputs) => { - let post_outputs = self.exprs(outputs.iter().map(|e| &**e), pred); - let post_inputs = self.exprs(inputs.iter().map(|e| &**e), post_outputs); - self.add_ast_node(expr.id, &[post_inputs]) - } - - hir::ExprClosure(..) | - hir::ExprLit(..) | - hir::ExprPath(..) => { - self.straightline(expr, pred, None::.iter()) - } - } - } - - fn call<'b, I: Iterator>(&mut self, - call_expr: &hir::Expr, - pred: CFGIndex, - func_or_rcvr: &hir::Expr, - args: I) -> CFGIndex { - let method_call = ty::MethodCall::expr(call_expr.id); - let fn_ty = match self.tcx.tables.borrow().method_map.get(&method_call) { - Some(method) => method.ty, - None => self.tcx.expr_ty_adjusted(func_or_rcvr) - }; - - let func_or_rcvr_exit = self.expr(func_or_rcvr, pred); - let ret = self.straightline(call_expr, func_or_rcvr_exit, args); - if fn_ty.fn_ret().diverges() { - self.add_unreachable_node() - } else { - ret - } - } - - fn exprs<'b, I: Iterator>(&mut self, - exprs: I, - pred: CFGIndex) -> CFGIndex { - //! Constructs graph for `exprs` evaluated in order - exprs.fold(pred, |p, e| self.expr(e, p)) - } - - fn opt_expr(&mut self, - opt_expr: &Option>, - pred: CFGIndex) -> CFGIndex { - //! Constructs graph for `opt_expr` evaluated, if Some - opt_expr.iter().fold(pred, |p, e| self.expr(&e, p)) - } - - fn straightline<'b, I: Iterator>(&mut self, - expr: &hir::Expr, - pred: CFGIndex, - subexprs: I) -> CFGIndex { - //! Handles case of an expression that evaluates `subexprs` in order - - let subexprs_exit = self.exprs(subexprs, pred); - self.add_ast_node(expr.id, &[subexprs_exit]) - } - - fn match_(&mut self, id: ast::NodeId, discr: &hir::Expr, - arms: &[hir::Arm], pred: CFGIndex) -> CFGIndex { - // The CFG for match expression is quite complex, so no ASCII - // art for it (yet). - // - // The CFG generated below matches roughly what trans puts - // out. Each pattern and guard is visited in parallel, with - // arms containing multiple patterns generating multiple nodes - // for the same guard expression. The guard expressions chain - // into each other from top to bottom, with a specific - // exception to allow some additional valid programs - // (explained below). Trans differs slightly in that the - // pattern matching may continue after a guard but the visible - // behaviour should be the same. - // - // What is going on is explained in further comments. - - // Visit the discriminant expression - let discr_exit = self.expr(discr, pred); - - // Add a node for the exit of the match expression as a whole. - let expr_exit = self.add_ast_node(id, &[]); - - // Keep track of the previous guard expressions - let mut prev_guards = Vec::new(); - // Track if the previous pattern contained bindings or wildcards - let mut prev_has_bindings = false; - - for arm in arms { - // Add an exit node for when we've visited all the - // patterns and the guard (if there is one) in the arm. - let arm_exit = self.add_dummy_node(&[]); - - for pat in &arm.pats { - // Visit the pattern, coming from the discriminant exit - let mut pat_exit = self.pat(&pat, discr_exit); - - // If there is a guard expression, handle it here - if let Some(ref guard) = arm.guard { - // Add a dummy node for the previous guard - // expression to target - let guard_start = self.add_dummy_node(&[pat_exit]); - // Visit the guard expression - let guard_exit = self.expr(&guard, guard_start); - - let this_has_bindings = pat_util::pat_contains_bindings_or_wild( - &self.tcx.def_map.borrow(), &pat); - - // If both this pattern and the previous pattern - // were free of bindings, they must consist only - // of "constant" patterns. Note we cannot match an - // all-constant pattern, fail the guard, and then - // match *another* all-constant pattern. This is - // because if the previous pattern matches, then - // we *cannot* match this one, unless all the - // constants are the same (which is rejected by - // `check_match`). - // - // We can use this to be smarter about the flow - // along guards. If the previous pattern matched, - // then we know we will not visit the guard in - // this one (whether or not the guard succeeded), - // if the previous pattern failed, then we know - // the guard for that pattern will not have been - // visited. Thus, it is not possible to visit both - // the previous guard and the current one when - // both patterns consist only of constant - // sub-patterns. - // - // However, if the above does not hold, then all - // previous guards need to be wired to visit the - // current guard pattern. - if prev_has_bindings || this_has_bindings { - while let Some(prev) = prev_guards.pop() { - self.add_contained_edge(prev, guard_start); - } - } - - prev_has_bindings = this_has_bindings; - - // Push the guard onto the list of previous guards - prev_guards.push(guard_exit); - - // Update the exit node for the pattern - pat_exit = guard_exit; - } - - // Add an edge from the exit of this pattern to the - // exit of the arm - self.add_contained_edge(pat_exit, arm_exit); - } - - // Visit the body of this arm - let body_exit = self.expr(&arm.body, arm_exit); - - // Link the body to the exit of the expression - self.add_contained_edge(body_exit, expr_exit); - } - - expr_exit - } - - fn add_dummy_node(&mut self, preds: &[CFGIndex]) -> CFGIndex { - self.add_node(CFGNodeData::Dummy, preds) - } - - fn add_ast_node(&mut self, id: ast::NodeId, preds: &[CFGIndex]) -> CFGIndex { - assert!(id != ast::DUMMY_NODE_ID); - self.add_node(CFGNodeData::AST(id), preds) - } - - fn add_unreachable_node(&mut self) -> CFGIndex { - self.add_node(CFGNodeData::Unreachable, &[]) - } - - fn add_node(&mut self, data: CFGNodeData, preds: &[CFGIndex]) -> CFGIndex { - let node = self.graph.add_node(data); - for &pred in preds { - self.add_contained_edge(pred, node); - } - node - } - - fn add_contained_edge(&mut self, - source: CFGIndex, - target: CFGIndex) { - let data = CFGEdgeData {exiting_scopes: vec!() }; - self.graph.add_edge(source, target, data); - } - - fn add_exiting_edge(&mut self, - from_expr: &hir::Expr, - from_index: CFGIndex, - to_loop: LoopScope, - to_index: CFGIndex) { - let mut data = CFGEdgeData {exiting_scopes: vec!() }; - let mut scope = self.tcx.region_maps.node_extent(from_expr.id); - let target_scope = self.tcx.region_maps.node_extent(to_loop.loop_id); - while scope != target_scope { - data.exiting_scopes.push(scope.node_id(&self.tcx.region_maps)); - scope = self.tcx.region_maps.encl_scope(scope); - } - self.graph.add_edge(from_index, to_index, data); - } - - fn add_returning_edge(&mut self, - _from_expr: &hir::Expr, - from_index: CFGIndex) { - let mut data = CFGEdgeData { - exiting_scopes: vec!(), - }; - for &LoopScope { loop_id: id, .. } in self.loop_scopes.iter().rev() { - data.exiting_scopes.push(id); - } - self.graph.add_edge(from_index, self.fn_exit, data); - } - - fn find_scope(&self, - expr: &hir::Expr, - label: Option) -> LoopScope { - if label.is_none() { - return *self.loop_scopes.last().unwrap(); - } - - match self.tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def()) { - Some(Def::Label(loop_id)) => { - for l in &self.loop_scopes { - if l.loop_id == loop_id { - return *l; - } - } - self.tcx.sess.span_bug(expr.span, - &format!("no loop scope for id {}", loop_id)); - } - - r => { - self.tcx.sess.span_bug(expr.span, - &format!("bad entry `{:?}` in def_map for label", r)); - } - } - } -} diff --git a/src/librustc/middle/cfg/graphviz.rs b/src/librustc/middle/cfg/graphviz.rs deleted file mode 100644 index c9c712c2d6e..00000000000 --- a/src/librustc/middle/cfg/graphviz.rs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// This module provides linkage between rustc::middle::graph and -/// libgraphviz traits. - -// For clarity, rename the graphviz crate locally to dot. -use graphviz as dot; -use graphviz::IntoCow; - -use syntax::ast; - -use front::map as ast_map; -use middle::cfg; - -pub type Node<'a> = (cfg::CFGIndex, &'a cfg::CFGNode); -pub type Edge<'a> = &'a cfg::CFGEdge; - -pub struct LabelledCFG<'a, 'ast: 'a> { - pub ast_map: &'a ast_map::Map<'ast>, - pub cfg: &'a cfg::CFG, - pub name: String, - /// `labelled_edges` controls whether we emit labels on the edges - pub labelled_edges: bool, -} - -fn replace_newline_with_backslash_l(s: String) -> String { - // Replacing newlines with \\l causes each line to be left-aligned, - // improving presentation of (long) pretty-printed expressions. - if s.contains("\n") { - let mut s = s.replace("\n", "\\l"); - // Apparently left-alignment applies to the line that precedes - // \l, not the line that follows; so, add \l at end of string - // if not already present, ensuring last line gets left-aligned - // as well. - let mut last_two: Vec<_> = - s.chars().rev().take(2).collect(); - last_two.reverse(); - if last_two != ['\\', 'l'] { - s.push_str("\\l"); - } - s - } else { - s - } -} - -impl<'a, 'ast> dot::Labeller<'a> for LabelledCFG<'a, 'ast> { - type Node = Node<'a>; - type Edge = Edge<'a>; - fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new(&self.name[..]).unwrap() } - - fn node_id(&'a self, &(i,_): &Node<'a>) -> dot::Id<'a> { - dot::Id::new(format!("N{}", i.node_id())).unwrap() - } - - fn node_label(&'a self, &(i, n): &Node<'a>) -> dot::LabelText<'a> { - if i == self.cfg.entry { - dot::LabelText::LabelStr("entry".into_cow()) - } else if i == self.cfg.exit { - dot::LabelText::LabelStr("exit".into_cow()) - } else if n.data.id() == ast::DUMMY_NODE_ID { - dot::LabelText::LabelStr("(dummy_node)".into_cow()) - } else { - let s = self.ast_map.node_to_string(n.data.id()); - // left-aligns the lines - let s = replace_newline_with_backslash_l(s); - dot::LabelText::EscStr(s.into_cow()) - } - } - - fn edge_label(&self, e: &Edge<'a>) -> dot::LabelText<'a> { - let mut label = String::new(); - if !self.labelled_edges { - return dot::LabelText::EscStr(label.into_cow()); - } - let mut put_one = false; - for (i, &node_id) in e.data.exiting_scopes.iter().enumerate() { - if put_one { - label.push_str(",\\l"); - } else { - put_one = true; - } - let s = self.ast_map.node_to_string(node_id); - // left-aligns the lines - let s = replace_newline_with_backslash_l(s); - label.push_str(&format!("exiting scope_{} {}", - i, - &s[..])); - } - dot::LabelText::EscStr(label.into_cow()) - } -} - -impl<'a> dot::GraphWalk<'a> for &'a cfg::CFG { - type Node = Node<'a>; - type Edge = Edge<'a>; - fn nodes(&'a self) -> dot::Nodes<'a, Node<'a>> { - let mut v = Vec::new(); - self.graph.each_node(|i, nd| { v.push((i, nd)); true }); - v.into_cow() - } - fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> { - self.graph.all_edges().iter().collect() - } - fn source(&'a self, edge: &Edge<'a>) -> Node<'a> { - let i = edge.source(); - (i, self.graph.node(i)) - } - fn target(&'a self, edge: &Edge<'a>) -> Node<'a> { - let i = edge.target(); - (i, self.graph.node(i)) - } -} - -impl<'a, 'ast> dot::GraphWalk<'a> for LabelledCFG<'a, 'ast> -{ - type Node = Node<'a>; - type Edge = Edge<'a>; - fn nodes(&'a self) -> dot::Nodes<'a, Node<'a>> { self.cfg.nodes() } - fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> { self.cfg.edges() } - fn source(&'a self, edge: &Edge<'a>) -> Node<'a> { self.cfg.source(edge) } - fn target(&'a self, edge: &Edge<'a>) -> Node<'a> { self.cfg.target(edge) } -} diff --git a/src/librustc/middle/cfg/mod.rs b/src/librustc/middle/cfg/mod.rs deleted file mode 100644 index 394633c5911..00000000000 --- a/src/librustc/middle/cfg/mod.rs +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Module that constructs a control-flow graph representing an item. -//! Uses `Graph` as the underlying representation. - -use rustc_data_structures::graph; -use middle::ty::TyCtxt; -use syntax::ast; -use rustc_front::hir; - -mod construct; -pub mod graphviz; - -pub struct CFG { - pub graph: CFGGraph, - pub entry: CFGIndex, - pub exit: CFGIndex, -} - -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum CFGNodeData { - AST(ast::NodeId), - Entry, - Exit, - Dummy, - Unreachable, -} - -impl CFGNodeData { - pub fn id(&self) -> ast::NodeId { - if let CFGNodeData::AST(id) = *self { - id - } else { - ast::DUMMY_NODE_ID - } - } -} - -#[derive(Debug)] -pub struct CFGEdgeData { - pub exiting_scopes: Vec -} - -pub type CFGIndex = graph::NodeIndex; - -pub type CFGGraph = graph::Graph; - -pub type CFGNode = graph::Node; - -pub type CFGEdge = graph::Edge; - -impl CFG { - pub fn new(tcx: &TyCtxt, - blk: &hir::Block) -> CFG { - construct::construct(tcx, blk) - } - - pub fn node_is_reachable(&self, id: ast::NodeId) -> bool { - self.graph.depth_traverse(self.entry) - .any(|idx| self.graph.node_data(idx).id() == id) - } -} diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 3414d509d95..79e4b7c0901 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -22,12 +22,12 @@ use middle::def_id::{DefId}; use middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor}; use middle::expr_use_visitor::{LoanCause, MutateMode}; use middle::expr_use_visitor as euv; -use middle::infer; +use infer; use middle::mem_categorization::{cmt}; use middle::pat_util::*; -use middle::traits::ProjectionMode; -use middle::ty::*; -use middle::ty; +use traits::ProjectionMode; +use ty::*; +use ty; use std::cmp::Ordering; use std::fmt; use std::iter::{FromIterator, IntoIterator, repeat}; diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 5c881bcb396..fca2904979c 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -18,13 +18,13 @@ use front::map as ast_map; use front::map::blocks::FnLikeNode; use lint; use middle::cstore::{self, CrateStore, InlinedItem}; -use middle::{infer, traits}; +use {infer, traits}; use middle::def::Def; use middle::def_id::DefId; use middle::pat_util::def_to_path; -use middle::ty::{self, subst, Ty, TyCtxt}; -use middle::ty::util::IntTypeExt; -use middle::traits::ProjectionMode; +use ty::{self, subst, Ty, TyCtxt}; +use ty::util::IntTypeExt; +use traits::ProjectionMode; use middle::astconv_util::ast_ty_to_prim_ty; use util::nodemap::NodeMap; diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index aada2ca2743..a0dacd62268 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -26,7 +26,7 @@ use back::svh::Svh; use front::map as hir_map; use middle::def::{self, Def}; use middle::lang_items; -use middle::ty::{self, Ty, TyCtxt, VariantKind}; +use ty::{self, Ty, TyCtxt, VariantKind}; use middle::def_id::{DefId, DefIndex}; use mir::repr::Mir; use mir::mir_map::MirMap; @@ -498,8 +498,8 @@ pub mod tls { use serialize; use std::cell::Cell; use std::mem; - use middle::ty::{self, Ty, TyCtxt}; - use middle::ty::subst::Substs; + use ty::{self, Ty, TyCtxt}; + use ty::subst::Substs; use middle::def_id::DefId; pub trait EncodingContext<'tcx> { diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index d8cffa3c2c9..6468187e219 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -14,9 +14,9 @@ //! and thus uses bitvectors. Your job is simply to specify the so-called //! GEN and KILL bits for each expression. -use middle::cfg; -use middle::cfg::CFGIndex; -use middle::ty::TyCtxt; +use cfg; +use cfg::CFGIndex; +use ty::TyCtxt; use std::io; use std::mem; use std::usize; diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 4ceac287d19..2b8ed14701d 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -17,8 +17,8 @@ use front::map as ast_map; use rustc_front::hir::{self, PatKind}; use rustc_front::intravisit::{self, Visitor}; -use middle::{pat_util, privacy, ty}; -use middle::ty::TyCtxt; +use middle::{pat_util, privacy}; +use ty::{self, TyCtxt}; use middle::def::Def; use middle::def_id::{DefId}; use lint; @@ -84,7 +84,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } fn lookup_and_handle_definition(&mut self, id: &ast::NodeId) { - use middle::ty::TypeVariants::{TyEnum, TyStruct}; + use ty::TypeVariants::{TyEnum, TyStruct}; // If `bar` is a trait item, make sure to mark Foo as alive in `Foo::bar` self.tcx.tables.borrow().item_substs.get(id) diff --git a/src/librustc/middle/def.rs b/src/librustc/middle/def.rs index f832a871c8b..6cbcd41d84a 100644 --- a/src/librustc/middle/def.rs +++ b/src/librustc/middle/def.rs @@ -9,7 +9,7 @@ // except according to those terms. use middle::def_id::DefId; -use middle::ty::subst::ParamSpace; +use ty::subst::ParamSpace; use util::nodemap::NodeMap; use syntax::ast; use rustc_front::hir; diff --git a/src/librustc/middle/def_id.rs b/src/librustc/middle/def_id.rs index f5bdf28a4b1..a3b83ec5be4 100644 --- a/src/librustc/middle/def_id.rs +++ b/src/librustc/middle/def_id.rs @@ -9,7 +9,7 @@ // except according to those terms. use middle::cstore::LOCAL_CRATE; -use middle::ty; +use ty; use syntax::ast::CrateNum; use std::fmt; use std::u32; diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index d4ff4b797c8..fa949073f4e 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -14,8 +14,8 @@ use self::RootUnsafeContext::*; use dep_graph::DepNode; use middle::def::Def; -use middle::ty::{self, Ty, TyCtxt}; -use middle::ty::MethodCall; +use ty::{self, Ty, TyCtxt}; +use ty::MethodCall; use syntax::ast; use syntax::codemap::Span; diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index ded64fa1d30..744022d1d5e 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -22,9 +22,9 @@ use self::OverloadedCallType::*; use middle::pat_util; use middle::def::Def; use middle::def_id::{DefId}; -use middle::infer; +use infer; use middle::mem_categorization as mc; -use middle::ty::{self, TyCtxt, adjustment}; +use ty::{self, TyCtxt, adjustment}; use rustc_front::hir::{self, PatKind}; diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index cb45a3e2507..20f2c5ad43f 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -15,8 +15,8 @@ //! `TransitiveRelation` type and use that to decide when one free //! region outlives another and so forth. -use middle::ty::{self, TyCtxt, FreeRegion, Region}; -use middle::ty::wf::ImpliedBound; +use ty::{self, TyCtxt, FreeRegion, Region}; +use ty::wf::ImpliedBound; use rustc_data_structures::transitive_relation::TransitiveRelation; #[derive(Clone)] diff --git a/src/librustc/middle/infer/README.md b/src/librustc/middle/infer/README.md deleted file mode 100644 index c835189820e..00000000000 --- a/src/librustc/middle/infer/README.md +++ /dev/null @@ -1,237 +0,0 @@ -# Type inference engine - -This is loosely based on standard HM-type inference, but with an -extension to try and accommodate subtyping. There is nothing -principled about this extension; it's sound---I hope!---but it's a -heuristic, ultimately, and does not guarantee that it finds a valid -typing even if one exists (in fact, there are known scenarios where it -fails, some of which may eventually become problematic). - -## Key idea - -The main change is that each type variable T is associated with a -lower-bound L and an upper-bound U. L and U begin as bottom and top, -respectively, but gradually narrow in response to new constraints -being introduced. When a variable is finally resolved to a concrete -type, it can (theoretically) select any type that is a supertype of L -and a subtype of U. - -There are several critical invariants which we maintain: - -- the upper-bound of a variable only becomes lower and the lower-bound - only becomes higher over time; -- the lower-bound L is always a subtype of the upper bound U; -- the lower-bound L and upper-bound U never refer to other type variables, - but only to types (though those types may contain type variables). - -> An aside: if the terms upper- and lower-bound confuse you, think of -> "supertype" and "subtype". The upper-bound is a "supertype" -> (super=upper in Latin, or something like that anyway) and the lower-bound -> is a "subtype" (sub=lower in Latin). I find it helps to visualize -> a simple class hierarchy, like Java minus interfaces and -> primitive types. The class Object is at the root (top) and other -> types lie in between. The bottom type is then the Null type. -> So the tree looks like: -> -> ```text -> Object -> / \ -> String Other -> \ / -> (null) -> ``` -> -> So the upper bound type is the "supertype" and the lower bound is the -> "subtype" (also, super and sub mean upper and lower in Latin, or something -> like that anyway). - -## Satisfying constraints - -At a primitive level, there is only one form of constraint that the -inference understands: a subtype relation. So the outside world can -say "make type A a subtype of type B". If there are variables -involved, the inferencer will adjust their upper- and lower-bounds as -needed to ensure that this relation is satisfied. (We also allow "make -type A equal to type B", but this is translated into "A <: B" and "B -<: A") - -As stated above, we always maintain the invariant that type bounds -never refer to other variables. This keeps the inference relatively -simple, avoiding the scenario of having a kind of graph where we have -to pump constraints along and reach a fixed point, but it does impose -some heuristics in the case where the user is relating two type -variables A <: B. - -Combining two variables such that variable A will forever be a subtype -of variable B is the trickiest part of the algorithm because there is -often no right choice---that is, the right choice will depend on -future constraints which we do not yet know. The problem comes about -because both A and B have bounds that can be adjusted in the future. -Let's look at some of the cases that can come up. - -Imagine, to start, the best case, where both A and B have an upper and -lower bound (that is, the bounds are not top nor bot respectively). In -that case, if we're lucky, A.ub <: B.lb, and so we know that whatever -A and B should become, they will forever have the desired subtyping -relation. We can just leave things as they are. - -### Option 1: Unify - -However, suppose that A.ub is *not* a subtype of B.lb. In -that case, we must make a decision. One option is to unify A -and B so that they are one variable whose bounds are: - - UB = GLB(A.ub, B.ub) - LB = LUB(A.lb, B.lb) - -(Note that we will have to verify that LB <: UB; if it does not, the -types are not intersecting and there is an error) In that case, A <: B -holds trivially because A==B. However, we have now lost some -flexibility, because perhaps the user intended for A and B to end up -as different types and not the same type. - -Pictorally, what this does is to take two distinct variables with -(hopefully not completely) distinct type ranges and produce one with -the intersection. - -```text - B.ub B.ub - /\ / - A.ub / \ A.ub / - / \ / \ \ / - / X \ UB - / / \ \ / \ - / / / \ / / - \ \ / / \ / - \ X / LB - \ / \ / / \ - \ / \ / / \ - A.lb B.lb A.lb B.lb -``` - - -### Option 2: Relate UB/LB - -Another option is to keep A and B as distinct variables but set their -bounds in such a way that, whatever happens, we know that A <: B will hold. -This can be achieved by ensuring that A.ub <: B.lb. In practice there -are two ways to do that, depicted pictorially here: - -```text - Before Option #1 Option #2 - - B.ub B.ub B.ub - /\ / \ / \ - A.ub / \ A.ub /(B')\ A.ub /(B')\ - / \ / \ \ / / \ / / - / X \ __UB____/ UB / - / / \ \ / | | / - / / / \ / | | / - \ \ / / /(A')| | / - \ X / / LB ______LB/ - \ / \ / / / \ / (A')/ \ - \ / \ / \ / \ \ / \ - A.lb B.lb A.lb B.lb A.lb B.lb -``` - -In these diagrams, UB and LB are defined as before. As you can see, -the new ranges `A'` and `B'` are quite different from the range that -would be produced by unifying the variables. - -### What we do now - -Our current technique is to *try* (transactionally) to relate the -existing bounds of A and B, if there are any (i.e., if `UB(A) != top -&& LB(B) != bot`). If that succeeds, we're done. If it fails, then -we merge A and B into same variable. - -This is not clearly the correct course. For example, if `UB(A) != -top` but `LB(B) == bot`, we could conceivably set `LB(B)` to `UB(A)` -and leave the variables unmerged. This is sometimes the better -course, it depends on the program. - -The main case which fails today that I would like to support is: - -```text -fn foo(x: T, y: T) { ... } - -fn bar() { - let x: @mut int = @mut 3; - let y: @int = @3; - foo(x, y); -} -``` - -In principle, the inferencer ought to find that the parameter `T` to -`foo(x, y)` is `@const int`. Today, however, it does not; this is -because the type variable `T` is merged with the type variable for -`X`, and thus inherits its UB/LB of `@mut int`. This leaves no -flexibility for `T` to later adjust to accommodate `@int`. - -### What to do when not all bounds are present - -In the prior discussion we assumed that A.ub was not top and B.lb was -not bot. Unfortunately this is rarely the case. Often type variables -have "lopsided" bounds. For example, if a variable in the program has -been initialized but has not been used, then its corresponding type -variable will have a lower bound but no upper bound. When that -variable is then used, we would like to know its upper bound---but we -don't have one! In this case we'll do different things depending on -how the variable is being used. - -## Transactional support - -Whenever we adjust merge variables or adjust their bounds, we always -keep a record of the old value. This allows the changes to be undone. - -## Regions - -I've only talked about type variables here, but region variables -follow the same principle. They have upper- and lower-bounds. A -region A is a subregion of a region B if A being valid implies that B -is valid. This basically corresponds to the block nesting structure: -the regions for outer block scopes are superregions of those for inner -block scopes. - -## Integral and floating-point type variables - -There is a third variety of type variable that we use only for -inferring the types of unsuffixed integer literals. Integral type -variables differ from general-purpose type variables in that there's -no subtyping relationship among the various integral types, so instead -of associating each variable with an upper and lower bound, we just -use simple unification. Each integer variable is associated with at -most one integer type. Floating point types are handled similarly to -integral types. - -## GLB/LUB - -Computing the greatest-lower-bound and least-upper-bound of two -types/regions is generally straightforward except when type variables -are involved. In that case, we follow a similar "try to use the bounds -when possible but otherwise merge the variables" strategy. In other -words, `GLB(A, B)` where `A` and `B` are variables will often result -in `A` and `B` being merged and the result being `A`. - -## Type coercion - -We have a notion of assignability which differs somewhat from -subtyping; in particular it may cause region borrowing to occur. See -the big comment later in this file on Type Coercion for specifics. - -### In conclusion - -I showed you three ways to relate `A` and `B`. There are also more, -of course, though I'm not sure if there are any more sensible options. -The main point is that there are various options, each of which -produce a distinct range of types for `A` and `B`. Depending on what -the correct values for A and B are, one of these options will be the -right choice: but of course we don't know the right values for A and B -yet, that's what we're trying to find! In our code, we opt to unify -(Option #1). - -# Implementation details - -We make use of a trait-like implementation strategy to consolidate -duplicated code between subtypes, GLB, and LUB computations. See the -section on "Type Combining" below for details. diff --git a/src/librustc/middle/infer/bivariate.rs b/src/librustc/middle/infer/bivariate.rs deleted file mode 100644 index 76a87675e3d..00000000000 --- a/src/librustc/middle/infer/bivariate.rs +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Applies the "bivariance relationship" to two types and/or regions. -//! If (A,B) are bivariant then either A <: B or B <: A. It occurs -//! when type/lifetime parameters are unconstrained. Usually this is -//! an error, but we permit it in the specific case where a type -//! parameter is constrained in a where-clause via an associated type. -//! -//! There are several ways one could implement bivariance. You could -//! just do nothing at all, for example, or you could fully verify -//! that one of the two subtyping relationships hold. We choose to -//! thread a middle line: we relate types up to regions, but ignore -//! all region relationships. -//! -//! At one point, handling bivariance in this fashion was necessary -//! for inference, but I'm actually not sure if that is true anymore. -//! In particular, it might be enough to say (A,B) are bivariant for -//! all (A,B). - -use super::combine::{self, CombineFields}; -use super::type_variable::{BiTo}; - -use middle::ty::{self, Ty, TyCtxt}; -use middle::ty::TyVar; -use middle::ty::relate::{Relate, RelateResult, TypeRelation}; - -pub struct Bivariate<'a, 'tcx: 'a> { - fields: CombineFields<'a, 'tcx> -} - -impl<'a, 'tcx> Bivariate<'a, 'tcx> { - pub fn new(fields: CombineFields<'a, 'tcx>) -> Bivariate<'a, 'tcx> { - Bivariate { fields: fields } - } -} - -impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Bivariate<'a, 'tcx> { - fn tag(&self) -> &'static str { "Bivariate" } - - fn tcx(&self) -> &'a TyCtxt<'tcx> { self.fields.tcx() } - - fn a_is_expected(&self) -> bool { self.fields.a_is_expected } - - fn relate_with_variance>(&mut self, - variance: ty::Variance, - a: &T, - b: &T) - -> RelateResult<'tcx, T> - { - match variance { - // If we have Foo and Foo is invariant w/r/t A, - // and we want to assert that - // - // Foo <: Foo || - // Foo <: Foo - // - // then still A must equal B. - ty::Invariant => self.relate(a, b), - - ty::Covariant => self.relate(a, b), - ty::Bivariant => self.relate(a, b), - ty::Contravariant => self.relate(a, b), - } - } - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - debug!("{}.tys({:?}, {:?})", self.tag(), - a, b); - if a == b { return Ok(a); } - - let infcx = self.fields.infcx; - let a = infcx.type_variables.borrow_mut().replace_if_possible(a); - let b = infcx.type_variables.borrow_mut().replace_if_possible(b); - match (&a.sty, &b.sty) { - (&ty::TyInfer(TyVar(a_id)), &ty::TyInfer(TyVar(b_id))) => { - infcx.type_variables.borrow_mut().relate_vars(a_id, BiTo, b_id); - Ok(a) - } - - (&ty::TyInfer(TyVar(a_id)), _) => { - self.fields.instantiate(b, BiTo, a_id)?; - Ok(a) - } - - (_, &ty::TyInfer(TyVar(b_id))) => { - self.fields.instantiate(a, BiTo, b_id)?; - Ok(a) - } - - _ => { - combine::super_combine_tys(self.fields.infcx, self, a, b) - } - } - } - - fn regions(&mut self, a: ty::Region, _: ty::Region) -> RelateResult<'tcx, ty::Region> { - Ok(a) - } - - fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) - -> RelateResult<'tcx, ty::Binder> - where T: Relate<'a,'tcx> - { - let a1 = self.tcx().erase_late_bound_regions(a); - let b1 = self.tcx().erase_late_bound_regions(b); - let c = self.relate(&a1, &b1)?; - Ok(ty::Binder(c)) - } -} diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs deleted file mode 100644 index f67389e3c3b..00000000000 --- a/src/librustc/middle/infer/combine.rs +++ /dev/null @@ -1,403 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/////////////////////////////////////////////////////////////////////////// -// # Type combining -// -// There are four type combiners: equate, sub, lub, and glb. Each -// implements the trait `Combine` and contains methods for combining -// two instances of various things and yielding a new instance. These -// combiner methods always yield a `Result`. There is a lot of -// common code for these operations, implemented as default methods on -// the `Combine` trait. -// -// Each operation may have side-effects on the inference context, -// though these can be unrolled using snapshots. On success, the -// LUB/GLB operations return the appropriate bound. The Eq and Sub -// operations generally return the first operand. -// -// ## Contravariance -// -// When you are relating two things which have a contravariant -// relationship, you should use `contratys()` or `contraregions()`, -// rather than inversing the order of arguments! This is necessary -// because the order of arguments is not relevant for LUB and GLB. It -// is also useful to track which value is the "expected" value in -// terms of error reporting. - -use super::bivariate::Bivariate; -use super::equate::Equate; -use super::glb::Glb; -use super::lub::Lub; -use super::sub::Sub; -use super::{InferCtxt}; -use super::{MiscVariable, TypeTrace}; -use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf}; - -use middle::ty::{IntType, UintType}; -use middle::ty::{self, Ty, TyCtxt}; -use middle::ty::error::TypeError; -use middle::ty::fold::{TypeFolder, TypeFoldable}; -use middle::ty::relate::{Relate, RelateResult, TypeRelation}; - -use syntax::ast; -use syntax::codemap::Span; - -#[derive(Clone)] -pub struct CombineFields<'a, 'tcx: 'a> { - pub infcx: &'a InferCtxt<'a, 'tcx>, - pub a_is_expected: bool, - pub trace: TypeTrace<'tcx>, - pub cause: Option, -} - -pub fn super_combine_tys<'a,'tcx:'a,R>(infcx: &InferCtxt<'a, 'tcx>, - relation: &mut R, - a: Ty<'tcx>, - b: Ty<'tcx>) - -> RelateResult<'tcx, Ty<'tcx>> - where R: TypeRelation<'a,'tcx> -{ - let a_is_expected = relation.a_is_expected(); - - match (&a.sty, &b.sty) { - // Relate integral variables to other types - (&ty::TyInfer(ty::IntVar(a_id)), &ty::TyInfer(ty::IntVar(b_id))) => { - infcx.int_unification_table - .borrow_mut() - .unify_var_var(a_id, b_id) - .map_err(|e| int_unification_error(a_is_expected, e))?; - Ok(a) - } - (&ty::TyInfer(ty::IntVar(v_id)), &ty::TyInt(v)) => { - unify_integral_variable(infcx, a_is_expected, v_id, IntType(v)) - } - (&ty::TyInt(v), &ty::TyInfer(ty::IntVar(v_id))) => { - unify_integral_variable(infcx, !a_is_expected, v_id, IntType(v)) - } - (&ty::TyInfer(ty::IntVar(v_id)), &ty::TyUint(v)) => { - unify_integral_variable(infcx, a_is_expected, v_id, UintType(v)) - } - (&ty::TyUint(v), &ty::TyInfer(ty::IntVar(v_id))) => { - unify_integral_variable(infcx, !a_is_expected, v_id, UintType(v)) - } - - // Relate floating-point variables to other types - (&ty::TyInfer(ty::FloatVar(a_id)), &ty::TyInfer(ty::FloatVar(b_id))) => { - infcx.float_unification_table - .borrow_mut() - .unify_var_var(a_id, b_id) - .map_err(|e| float_unification_error(relation.a_is_expected(), e))?; - Ok(a) - } - (&ty::TyInfer(ty::FloatVar(v_id)), &ty::TyFloat(v)) => { - unify_float_variable(infcx, a_is_expected, v_id, v) - } - (&ty::TyFloat(v), &ty::TyInfer(ty::FloatVar(v_id))) => { - unify_float_variable(infcx, !a_is_expected, v_id, v) - } - - // All other cases of inference are errors - (&ty::TyInfer(_), _) | - (_, &ty::TyInfer(_)) => { - Err(TypeError::Sorts(ty::relate::expected_found(relation, &a, &b))) - } - - - _ => { - ty::relate::super_relate_tys(relation, a, b) - } - } -} - -fn unify_integral_variable<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, - vid_is_expected: bool, - vid: ty::IntVid, - val: ty::IntVarValue) - -> RelateResult<'tcx, Ty<'tcx>> -{ - infcx.int_unification_table - .borrow_mut() - .unify_var_value(vid, val) - .map_err(|e| int_unification_error(vid_is_expected, e))?; - match val { - IntType(v) => Ok(infcx.tcx.mk_mach_int(v)), - UintType(v) => Ok(infcx.tcx.mk_mach_uint(v)), - } -} - -fn unify_float_variable<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, - vid_is_expected: bool, - vid: ty::FloatVid, - val: ast::FloatTy) - -> RelateResult<'tcx, Ty<'tcx>> -{ - infcx.float_unification_table - .borrow_mut() - .unify_var_value(vid, val) - .map_err(|e| float_unification_error(vid_is_expected, e))?; - Ok(infcx.tcx.mk_mach_float(val)) -} - -impl<'a, 'tcx> CombineFields<'a, 'tcx> { - pub fn tcx(&self) -> &'a TyCtxt<'tcx> { - self.infcx.tcx - } - - pub fn switch_expected(&self) -> CombineFields<'a, 'tcx> { - CombineFields { - a_is_expected: !self.a_is_expected, - ..(*self).clone() - } - } - - pub fn equate(&self) -> Equate<'a, 'tcx> { - Equate::new(self.clone()) - } - - pub fn bivariate(&self) -> Bivariate<'a, 'tcx> { - Bivariate::new(self.clone()) - } - - pub fn sub(&self) -> Sub<'a, 'tcx> { - Sub::new(self.clone()) - } - - pub fn lub(&self) -> Lub<'a, 'tcx> { - Lub::new(self.clone()) - } - - pub fn glb(&self) -> Glb<'a, 'tcx> { - Glb::new(self.clone()) - } - - pub fn instantiate(&self, - a_ty: Ty<'tcx>, - dir: RelationDir, - b_vid: ty::TyVid) - -> RelateResult<'tcx, ()> - { - let mut stack = Vec::new(); - stack.push((a_ty, dir, b_vid)); - loop { - // For each turn of the loop, we extract a tuple - // - // (a_ty, dir, b_vid) - // - // to relate. Here dir is either SubtypeOf or - // SupertypeOf. The idea is that we should ensure that - // the type `a_ty` is a subtype or supertype (respectively) of the - // type to which `b_vid` is bound. - // - // If `b_vid` has not yet been instantiated with a type - // (which is always true on the first iteration, but not - // necessarily true on later iterations), we will first - // instantiate `b_vid` with a *generalized* version of - // `a_ty`. Generalization introduces other inference - // variables wherever subtyping could occur (at time of - // this writing, this means replacing free regions with - // region variables). - let (a_ty, dir, b_vid) = match stack.pop() { - None => break, - Some(e) => e, - }; - // Get the actual variable that b_vid has been inferred to - let (b_vid, b_ty) = { - let mut variables = self.infcx.type_variables.borrow_mut(); - let b_vid = variables.root_var(b_vid); - (b_vid, variables.probe_root(b_vid)) - }; - - debug!("instantiate(a_ty={:?} dir={:?} b_vid={:?})", - a_ty, - dir, - b_vid); - - // Check whether `vid` has been instantiated yet. If not, - // make a generalized form of `ty` and instantiate with - // that. - let b_ty = match b_ty { - Some(t) => t, // ...already instantiated. - None => { // ...not yet instantiated: - // Generalize type if necessary. - let generalized_ty = match dir { - EqTo => self.generalize(a_ty, b_vid, false), - BiTo | SupertypeOf | SubtypeOf => self.generalize(a_ty, b_vid, true), - }?; - debug!("instantiate(a_ty={:?}, dir={:?}, \ - b_vid={:?}, generalized_ty={:?})", - a_ty, dir, b_vid, - generalized_ty); - self.infcx.type_variables - .borrow_mut() - .instantiate_and_push( - b_vid, generalized_ty, &mut stack); - generalized_ty - } - }; - - // The original triple was `(a_ty, dir, b_vid)` -- now we have - // resolved `b_vid` to `b_ty`, so apply `(a_ty, dir, b_ty)`: - // - // FIXME(#16847): This code is non-ideal because all these subtype - // relations wind up attributed to the same spans. We need - // to associate causes/spans with each of the relations in - // the stack to get this right. - match dir { - BiTo => self.bivariate().relate(&a_ty, &b_ty), - EqTo => self.equate().relate(&a_ty, &b_ty), - SubtypeOf => self.sub().relate(&a_ty, &b_ty), - SupertypeOf => self.sub().relate_with_variance(ty::Contravariant, &a_ty, &b_ty), - }?; - } - - Ok(()) - } - - /// Attempts to generalize `ty` for the type variable `for_vid`. This checks for cycle -- that - /// is, whether the type `ty` references `for_vid`. If `make_region_vars` is true, it will also - /// replace all regions with fresh variables. Returns `TyError` in the case of a cycle, `Ok` - /// otherwise. - fn generalize(&self, - ty: Ty<'tcx>, - for_vid: ty::TyVid, - make_region_vars: bool) - -> RelateResult<'tcx, Ty<'tcx>> - { - let mut generalize = Generalizer { - infcx: self.infcx, - span: self.trace.origin.span(), - for_vid: for_vid, - make_region_vars: make_region_vars, - cycle_detected: false - }; - let u = ty.fold_with(&mut generalize); - if generalize.cycle_detected { - Err(TypeError::CyclicTy) - } else { - Ok(u) - } - } -} - -struct Generalizer<'cx, 'tcx:'cx> { - infcx: &'cx InferCtxt<'cx, 'tcx>, - span: Span, - for_vid: ty::TyVid, - make_region_vars: bool, - cycle_detected: bool, -} - -impl<'cx, 'tcx> ty::fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> { - fn tcx(&self) -> &TyCtxt<'tcx> { - self.infcx.tcx - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - // Check to see whether the type we are genealizing references - // `vid`. At the same time, also update any type variables to - // the values that they are bound to. This is needed to truly - // check for cycles, but also just makes things readable. - // - // (In particular, you could have something like `$0 = Box<$1>` - // where `$1` has already been instantiated with `Box<$0>`) - match t.sty { - ty::TyInfer(ty::TyVar(vid)) => { - let mut variables = self.infcx.type_variables.borrow_mut(); - let vid = variables.root_var(vid); - if vid == self.for_vid { - self.cycle_detected = true; - self.tcx().types.err - } else { - match variables.probe_root(vid) { - Some(u) => { - drop(variables); - self.fold_ty(u) - } - None => t, - } - } - } - _ => { - t.super_fold_with(self) - } - } - } - - fn fold_region(&mut self, r: ty::Region) -> ty::Region { - match r { - // Never make variables for regions bound within the type itself. - ty::ReLateBound(..) => { return r; } - - // Early-bound regions should really have been substituted away before - // we get to this point. - ty::ReEarlyBound(..) => { - self.tcx().sess.span_bug( - self.span, - &format!("Encountered early bound region when generalizing: {:?}", - r)); - } - - // Always make a fresh region variable for skolemized regions; - // the higher-ranked decision procedures rely on this. - ty::ReSkolemized(..) => { } - - // For anything else, we make a region variable, unless we - // are *equating*, in which case it's just wasteful. - ty::ReEmpty | - ty::ReStatic | - ty::ReScope(..) | - ty::ReVar(..) | - ty::ReFree(..) => { - if !self.make_region_vars { - return r; - } - } - } - - // FIXME: This is non-ideal because we don't give a - // very descriptive origin for this region variable. - self.infcx.next_region_var(MiscVariable(self.span)) - } -} - -pub trait RelateResultCompare<'tcx, T> { - fn compare(&self, t: T, f: F) -> RelateResult<'tcx, T> where - F: FnOnce() -> TypeError<'tcx>; -} - -impl<'tcx, T:Clone + PartialEq> RelateResultCompare<'tcx, T> for RelateResult<'tcx, T> { - fn compare(&self, t: T, f: F) -> RelateResult<'tcx, T> where - F: FnOnce() -> TypeError<'tcx>, - { - self.clone().and_then(|s| { - if s == t { - self.clone() - } else { - Err(f()) - } - }) - } -} - -fn int_unification_error<'tcx>(a_is_expected: bool, v: (ty::IntVarValue, ty::IntVarValue)) - -> TypeError<'tcx> -{ - let (a, b) = v; - TypeError::IntMismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b)) -} - -fn float_unification_error<'tcx>(a_is_expected: bool, - v: (ast::FloatTy, ast::FloatTy)) - -> TypeError<'tcx> -{ - let (a, b) = v; - TypeError::FloatMismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b)) -} diff --git a/src/librustc/middle/infer/equate.rs b/src/librustc/middle/infer/equate.rs deleted file mode 100644 index dd576c75ba3..00000000000 --- a/src/librustc/middle/infer/equate.rs +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::combine::{self, CombineFields}; -use super::higher_ranked::HigherRankedRelations; -use super::{Subtype}; -use super::type_variable::{EqTo}; - -use middle::ty::{self, Ty, TyCtxt}; -use middle::ty::TyVar; -use middle::ty::relate::{Relate, RelateResult, TypeRelation}; - -/// Ensures `a` is made equal to `b`. Returns `a` on success. -pub struct Equate<'a, 'tcx: 'a> { - fields: CombineFields<'a, 'tcx> -} - -impl<'a, 'tcx> Equate<'a, 'tcx> { - pub fn new(fields: CombineFields<'a, 'tcx>) -> Equate<'a, 'tcx> { - Equate { fields: fields } - } -} - -impl<'a, 'tcx> TypeRelation<'a,'tcx> for Equate<'a, 'tcx> { - fn tag(&self) -> &'static str { "Equate" } - - fn tcx(&self) -> &'a TyCtxt<'tcx> { self.fields.tcx() } - - fn a_is_expected(&self) -> bool { self.fields.a_is_expected } - - fn relate_with_variance>(&mut self, - _: ty::Variance, - a: &T, - b: &T) - -> RelateResult<'tcx, T> - { - self.relate(a, b) - } - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - debug!("{}.tys({:?}, {:?})", self.tag(), - a, b); - if a == b { return Ok(a); } - - let infcx = self.fields.infcx; - let a = infcx.type_variables.borrow_mut().replace_if_possible(a); - let b = infcx.type_variables.borrow_mut().replace_if_possible(b); - match (&a.sty, &b.sty) { - (&ty::TyInfer(TyVar(a_id)), &ty::TyInfer(TyVar(b_id))) => { - infcx.type_variables.borrow_mut().relate_vars(a_id, EqTo, b_id); - Ok(a) - } - - (&ty::TyInfer(TyVar(a_id)), _) => { - self.fields.instantiate(b, EqTo, a_id)?; - Ok(a) - } - - (_, &ty::TyInfer(TyVar(b_id))) => { - self.fields.instantiate(a, EqTo, b_id)?; - Ok(a) - } - - _ => { - combine::super_combine_tys(self.fields.infcx, self, a, b)?; - Ok(a) - } - } - } - - fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> { - debug!("{}.regions({:?}, {:?})", - self.tag(), - a, - b); - let origin = Subtype(self.fields.trace.clone()); - self.fields.infcx.region_vars.make_eqregion(origin, a, b); - Ok(a) - } - - fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) - -> RelateResult<'tcx, ty::Binder> - where T: Relate<'a, 'tcx> - { - self.fields.higher_ranked_sub(a, b)?; - self.fields.higher_ranked_sub(b, a) - } -} diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs deleted file mode 100644 index 7a1da774531..00000000000 --- a/src/librustc/middle/infer/error_reporting.rs +++ /dev/null @@ -1,2050 +0,0 @@ -// Copyright 2012-2013 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Error Reporting Code for the inference engine -//! -//! Because of the way inference, and in particular region inference, -//! works, it often happens that errors are not detected until far after -//! the relevant line of code has been type-checked. Therefore, there is -//! an elaborate system to track why a particular constraint in the -//! inference graph arose so that we can explain to the user what gave -//! rise to a particular error. -//! -//! The basis of the system are the "origin" types. An "origin" is the -//! reason that a constraint or inference variable arose. There are -//! different "origin" enums for different kinds of constraints/variables -//! (e.g., `TypeOrigin`, `RegionVariableOrigin`). An origin always has -//! a span, but also more information so that we can generate a meaningful -//! error message. -//! -//! Having a catalogue of all the different reasons an error can arise is -//! also useful for other reasons, like cross-referencing FAQs etc, though -//! we are not really taking advantage of this yet. -//! -//! # Region Inference -//! -//! Region inference is particularly tricky because it always succeeds "in -//! the moment" and simply registers a constraint. Then, at the end, we -//! can compute the full graph and report errors, so we need to be able to -//! store and later report what gave rise to the conflicting constraints. -//! -//! # Subtype Trace -//! -//! Determining whether `T1 <: T2` often involves a number of subtypes and -//! subconstraints along the way. A "TypeTrace" is an extended version -//! of an origin that traces the types and other values that were being -//! compared. It is not necessarily comprehensive (in fact, at the time of -//! this writing it only tracks the root values being compared) but I'd -//! like to extend it to include significant "waypoints". For example, if -//! you are comparing `(T1, T2) <: (T3, T4)`, and the problem is that `T2 -//! <: T4` fails, I'd like the trace to include enough information to say -//! "in the 2nd element of the tuple". Similarly, failures when comparing -//! arguments or return types in fn types should be able to cite the -//! specific position, etc. -//! -//! # Reality vs plan -//! -//! Of course, there is still a LOT of code in typeck that has yet to be -//! ported to this system, and which relies on string concatenation at the -//! time of error detection. - -use self::FreshOrKept::*; - -use super::InferCtxt; -use super::TypeTrace; -use super::SubregionOrigin; -use super::RegionVariableOrigin; -use super::ValuePairs; -use super::region_inference::RegionResolutionError; -use super::region_inference::ConcreteFailure; -use super::region_inference::SubSupConflict; -use super::region_inference::GenericBoundFailure; -use super::region_inference::GenericKind; -use super::region_inference::ProcessedErrors; -use super::region_inference::ProcessedErrorOrigin; -use super::region_inference::SameRegions; - -use std::collections::HashSet; - -use front::map as ast_map; -use rustc_front::hir; -use rustc_front::print::pprust; - -use middle::cstore::CrateStore; -use middle::def::Def; -use middle::def_id::DefId; -use middle::infer::{self, TypeOrigin}; -use middle::region; -use middle::ty::subst; -use middle::ty::{self, Ty, TyCtxt, TypeFoldable}; -use middle::ty::{Region, ReFree}; -use middle::ty::error::TypeError; - -use std::cell::{Cell, RefCell}; -use std::char::from_u32; -use std::fmt; -use syntax::ast; -use syntax::errors::DiagnosticBuilder; -use syntax::codemap::{self, Pos, Span}; -use syntax::parse::token; -use syntax::ptr::P; - -impl<'tcx> TyCtxt<'tcx> { - pub fn note_and_explain_region(&self, - err: &mut DiagnosticBuilder, - prefix: &str, - region: ty::Region, - suffix: &str) { - fn item_scope_tag(item: &hir::Item) -> &'static str { - match item.node { - hir::ItemImpl(..) => "impl", - hir::ItemStruct(..) => "struct", - hir::ItemEnum(..) => "enum", - hir::ItemTrait(..) => "trait", - hir::ItemFn(..) => "function body", - _ => "item" - } - } - - fn explain_span(tcx: &TyCtxt, heading: &str, span: Span) - -> (String, Option) { - let lo = tcx.sess.codemap().lookup_char_pos_adj(span.lo); - (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize()), - Some(span)) - } - - let (description, span) = match region { - ty::ReScope(scope) => { - let new_string; - let unknown_scope = || { - format!("{}unknown scope: {:?}{}. Please report a bug.", - prefix, scope, suffix) - }; - let span = match scope.span(&self.region_maps, &self.map) { - Some(s) => s, - None => { - err.note(&unknown_scope()); - return; - } - }; - let tag = match self.map.find(scope.node_id(&self.region_maps)) { - Some(ast_map::NodeBlock(_)) => "block", - Some(ast_map::NodeExpr(expr)) => match expr.node { - hir::ExprCall(..) => "call", - hir::ExprMethodCall(..) => "method call", - hir::ExprMatch(_, _, hir::MatchSource::IfLetDesugar { .. }) => "if let", - hir::ExprMatch(_, _, hir::MatchSource::WhileLetDesugar) => "while let", - hir::ExprMatch(_, _, hir::MatchSource::ForLoopDesugar) => "for", - hir::ExprMatch(..) => "match", - _ => "expression", - }, - Some(ast_map::NodeStmt(_)) => "statement", - Some(ast_map::NodeItem(it)) => item_scope_tag(&it), - Some(_) | None => { - err.span_note(span, &unknown_scope()); - return; - } - }; - let scope_decorated_tag = match self.region_maps.code_extent_data(scope) { - region::CodeExtentData::Misc(_) => tag, - region::CodeExtentData::CallSiteScope { .. } => { - "scope of call-site for function" - } - region::CodeExtentData::ParameterScope { .. } => { - "scope of parameters for function" - } - region::CodeExtentData::DestructionScope(_) => { - new_string = format!("destruction scope surrounding {}", tag); - &new_string[..] - } - region::CodeExtentData::Remainder(r) => { - new_string = format!("block suffix following statement {}", - r.first_statement_index); - &new_string[..] - } - }; - explain_span(self, scope_decorated_tag, span) - } - - ty::ReFree(ref fr) => { - let prefix = match fr.bound_region { - ty::BrAnon(idx) => { - format!("the anonymous lifetime #{} defined on", idx + 1) - } - ty::BrFresh(_) => "an anonymous lifetime defined on".to_owned(), - _ => { - format!("the lifetime {} as defined on", - fr.bound_region) - } - }; - - match self.map.find(fr.scope.node_id(&self.region_maps)) { - Some(ast_map::NodeBlock(ref blk)) => { - let (msg, opt_span) = explain_span(self, "block", blk.span); - (format!("{} {}", prefix, msg), opt_span) - } - Some(ast_map::NodeItem(it)) => { - let tag = item_scope_tag(&it); - let (msg, opt_span) = explain_span(self, tag, it.span); - (format!("{} {}", prefix, msg), opt_span) - } - Some(_) | None => { - // this really should not happen, but it does: - // FIXME(#27942) - (format!("{} unknown free region bounded by scope {:?}", - prefix, fr.scope), None) - } - } - } - - ty::ReStatic => ("the static lifetime".to_owned(), None), - - ty::ReEmpty => ("the empty lifetime".to_owned(), None), - - ty::ReEarlyBound(ref data) => (data.name.to_string(), None), - - // FIXME(#13998) ReSkolemized should probably print like - // ReFree rather than dumping Debug output on the user. - // - // We shouldn't really be having unification failures with ReVar - // and ReLateBound though. - ty::ReSkolemized(..) | ty::ReVar(_) | ty::ReLateBound(..) => { - (format!("lifetime {:?}", region), None) - } - }; - let message = format!("{}{}{}", prefix, description, suffix); - if let Some(span) = span { - err.span_note(span, &message); - } else { - err.note(&message); - } - } -} - -pub trait ErrorReporting<'tcx> { - fn report_region_errors(&self, - errors: &Vec>); - - fn process_errors(&self, errors: &Vec>) - -> Option>>; - - fn report_type_error(&self, - trace: TypeTrace<'tcx>, - terr: &TypeError<'tcx>) - -> DiagnosticBuilder<'tcx>; - - fn check_and_note_conflicting_crates(&self, - err: &mut DiagnosticBuilder, - terr: &TypeError<'tcx>, - sp: Span); - - fn report_and_explain_type_error(&self, - trace: TypeTrace<'tcx>, - terr: &TypeError<'tcx>) - -> DiagnosticBuilder<'tcx>; - - fn values_str(&self, values: &ValuePairs<'tcx>) -> Option; - - fn expected_found_str + TypeFoldable<'tcx>>( - &self, - exp_found: &ty::error::ExpectedFound) - -> Option; - - fn report_concrete_failure(&self, - origin: SubregionOrigin<'tcx>, - sub: Region, - sup: Region) - -> DiagnosticBuilder<'tcx>; - - fn report_generic_bound_failure(&self, - origin: SubregionOrigin<'tcx>, - kind: GenericKind<'tcx>, - sub: Region); - - fn report_sub_sup_conflict(&self, - var_origin: RegionVariableOrigin, - sub_origin: SubregionOrigin<'tcx>, - sub_region: Region, - sup_origin: SubregionOrigin<'tcx>, - sup_region: Region); - - fn report_processed_errors(&self, - origins: &[ProcessedErrorOrigin<'tcx>], - same_regions: &[SameRegions]); - - fn give_suggestion(&self, err: &mut DiagnosticBuilder, same_regions: &[SameRegions]); -} - -trait ErrorReportingHelpers<'tcx> { - fn report_inference_failure(&self, - var_origin: RegionVariableOrigin) - -> DiagnosticBuilder<'tcx>; - - fn note_region_origin(&self, - err: &mut DiagnosticBuilder, - origin: &SubregionOrigin<'tcx>); - - fn give_expl_lifetime_param(&self, - err: &mut DiagnosticBuilder, - decl: &hir::FnDecl, - unsafety: hir::Unsafety, - constness: hir::Constness, - name: ast::Name, - opt_explicit_self: Option<&hir::ExplicitSelf_>, - generics: &hir::Generics, - span: Span); -} - -impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { - fn report_region_errors(&self, - errors: &Vec>) { - debug!("report_region_errors(): {} errors to start", errors.len()); - - // try to pre-process the errors, which will group some of them - // together into a `ProcessedErrors` group: - let processed_errors = self.process_errors(errors); - let errors = processed_errors.as_ref().unwrap_or(errors); - - debug!("report_region_errors: {} errors after preprocessing", errors.len()); - - for error in errors { - match error.clone() { - ConcreteFailure(origin, sub, sup) => { - self.report_concrete_failure(origin, sub, sup).emit(); - } - - GenericBoundFailure(kind, param_ty, sub) => { - self.report_generic_bound_failure(kind, param_ty, sub); - } - - SubSupConflict(var_origin, - sub_origin, sub_r, - sup_origin, sup_r) => { - self.report_sub_sup_conflict(var_origin, - sub_origin, sub_r, - sup_origin, sup_r); - } - - ProcessedErrors(ref origins, - ref same_regions) => { - if !same_regions.is_empty() { - self.report_processed_errors(origins, same_regions); - } - } - } - } - } - - // This method goes through all the errors and try to group certain types - // of error together, for the purpose of suggesting explicit lifetime - // parameters to the user. This is done so that we can have a more - // complete view of what lifetimes should be the same. - // If the return value is an empty vector, it means that processing - // failed (so the return value of this method should not be used). - // - // The method also attempts to weed out messages that seem like - // duplicates that will be unhelpful to the end-user. But - // obviously it never weeds out ALL errors. - fn process_errors(&self, errors: &Vec>) - -> Option>> { - debug!("process_errors()"); - let mut origins = Vec::new(); - - // we collect up ConcreteFailures and SubSupConflicts that are - // relating free-regions bound on the fn-header and group them - // together into this vector - let mut same_regions = Vec::new(); - - // here we put errors that we will not be able to process nicely - let mut other_errors = Vec::new(); - - // we collect up GenericBoundFailures in here. - let mut bound_failures = Vec::new(); - - for error in errors { - match *error { - ConcreteFailure(ref origin, sub, sup) => { - debug!("processing ConcreteFailure"); - match free_regions_from_same_fn(self.tcx, sub, sup) { - Some(ref same_frs) => { - origins.push( - ProcessedErrorOrigin::ConcreteFailure( - origin.clone(), - sub, - sup)); - append_to_same_regions(&mut same_regions, same_frs); - } - _ => { - other_errors.push(error.clone()); - } - } - } - SubSupConflict(ref var_origin, _, sub_r, _, sup_r) => { - debug!("processing SubSupConflict sub: {:?} sup: {:?}", sub_r, sup_r); - match free_regions_from_same_fn(self.tcx, sub_r, sup_r) { - Some(ref same_frs) => { - origins.push( - ProcessedErrorOrigin::VariableFailure( - var_origin.clone())); - append_to_same_regions(&mut same_regions, same_frs); - } - None => { - other_errors.push(error.clone()); - } - } - } - GenericBoundFailure(ref origin, ref kind, region) => { - bound_failures.push((origin.clone(), kind.clone(), region)); - } - ProcessedErrors(..) => { - panic!("should not encounter a `ProcessedErrors` yet: {:?}", error) - } - } - } - - // ok, let's pull together the errors, sorted in an order that - // we think will help user the best - let mut processed_errors = vec![]; - - // first, put the processed errors, if any - if !same_regions.is_empty() { - let common_scope_id = same_regions[0].scope_id; - for sr in &same_regions { - // Since ProcessedErrors is used to reconstruct the function - // declaration, we want to make sure that they are, in fact, - // from the same scope - if sr.scope_id != common_scope_id { - debug!("returning empty result from process_errors because - {} != {}", sr.scope_id, common_scope_id); - return None; - } - } - assert!(origins.len() > 0); - let pe = ProcessedErrors(origins, same_regions); - debug!("errors processed: {:?}", pe); - processed_errors.push(pe); - } - - // next, put the other misc errors - processed_errors.extend(other_errors); - - // finally, put the `T: 'a` errors, but only if there were no - // other errors. otherwise, these have a very high rate of - // being unhelpful in practice. This is because they are - // basically secondary checks that test the state of the - // region graph after the rest of inference is done, and the - // other kinds of errors indicate that the region constraint - // graph is internally inconsistent, so these test results are - // likely to be meaningless. - if processed_errors.is_empty() { - for (origin, kind, region) in bound_failures { - processed_errors.push(GenericBoundFailure(origin, kind, region)); - } - } - - // we should always wind up with SOME errors, unless there were no - // errors to start - assert!(if errors.len() > 0 {processed_errors.len() > 0} else {true}); - - return Some(processed_errors); - - #[derive(Debug)] - struct FreeRegionsFromSameFn { - sub_fr: ty::FreeRegion, - sup_fr: ty::FreeRegion, - scope_id: ast::NodeId - } - - impl FreeRegionsFromSameFn { - fn new(sub_fr: ty::FreeRegion, - sup_fr: ty::FreeRegion, - scope_id: ast::NodeId) - -> FreeRegionsFromSameFn { - FreeRegionsFromSameFn { - sub_fr: sub_fr, - sup_fr: sup_fr, - scope_id: scope_id - } - } - } - - fn free_regions_from_same_fn(tcx: &TyCtxt, - sub: Region, - sup: Region) - -> Option { - debug!("free_regions_from_same_fn(sub={:?}, sup={:?})", sub, sup); - let (scope_id, fr1, fr2) = match (sub, sup) { - (ReFree(fr1), ReFree(fr2)) => { - if fr1.scope != fr2.scope { - return None - } - assert!(fr1.scope == fr2.scope); - (fr1.scope.node_id(&tcx.region_maps), fr1, fr2) - }, - _ => return None - }; - let parent = tcx.map.get_parent(scope_id); - let parent_node = tcx.map.find(parent); - match parent_node { - Some(node) => match node { - ast_map::NodeItem(item) => match item.node { - hir::ItemFn(..) => { - Some(FreeRegionsFromSameFn::new(fr1, fr2, scope_id)) - }, - _ => None - }, - ast_map::NodeImplItem(..) | - ast_map::NodeTraitItem(..) => { - Some(FreeRegionsFromSameFn::new(fr1, fr2, scope_id)) - }, - _ => None - }, - None => { - debug!("no parent node of scope_id {}", scope_id); - None - } - } - } - - fn append_to_same_regions(same_regions: &mut Vec, - same_frs: &FreeRegionsFromSameFn) { - debug!("append_to_same_regions(same_regions={:?}, same_frs={:?})", - same_regions, same_frs); - let scope_id = same_frs.scope_id; - let (sub_fr, sup_fr) = (same_frs.sub_fr, same_frs.sup_fr); - for sr in same_regions.iter_mut() { - if sr.contains(&sup_fr.bound_region) && scope_id == sr.scope_id { - sr.push(sub_fr.bound_region); - return - } - } - same_regions.push(SameRegions { - scope_id: scope_id, - regions: vec!(sub_fr.bound_region, sup_fr.bound_region) - }) - } - } - - fn report_type_error(&self, - trace: TypeTrace<'tcx>, - terr: &TypeError<'tcx>) - -> DiagnosticBuilder<'tcx> { - let expected_found_str = match self.values_str(&trace.values) { - Some(v) => v, - None => { - return self.tcx.sess.diagnostic().struct_dummy(); /* derived error */ - } - }; - - let is_simple_error = if let &TypeError::Sorts(ref values) = terr { - values.expected.is_primitive() && values.found.is_primitive() - } else { - false - }; - - let expected_found_str = if is_simple_error { - expected_found_str - } else { - format!("{} ({})", expected_found_str, terr) - }; - - let mut err = struct_span_err!(self.tcx.sess, - trace.origin.span(), - E0308, - "{}: {}", - trace.origin, - expected_found_str); - - self.check_and_note_conflicting_crates(&mut err, terr, trace.origin.span()); - - match trace.origin { - TypeOrigin::MatchExpressionArm(_, arm_span, source) => match source { - hir::MatchSource::IfLetDesugar{..} => { - err.span_note(arm_span, "`if let` arm with an incompatible type"); - } - _ => { - err.span_note(arm_span, "match arm with an incompatible type"); - } - }, - _ => () - } - err - } - - /// Adds a note if the types come from similarly named crates - fn check_and_note_conflicting_crates(&self, - err: &mut DiagnosticBuilder, - terr: &TypeError<'tcx>, - sp: Span) { - let report_path_match = |err: &mut DiagnosticBuilder, did1: DefId, did2: DefId| { - // Only external crates, if either is from a local - // module we could have false positives - if !(did1.is_local() || did2.is_local()) && did1.krate != did2.krate { - let exp_path = self.tcx.with_path(did1, - |p| p.map(|x| x.to_string()) - .collect::>()); - let found_path = self.tcx.with_path(did2, - |p| p.map(|x| x.to_string()) - .collect::>()); - // We compare strings because PathMod and PathName can be different - // for imported and non-imported crates - if exp_path == found_path { - let crate_name = self.tcx.sess.cstore.crate_name(did1.krate); - err.span_note(sp, &format!("Perhaps two different versions \ - of crate `{}` are being used?", - crate_name)); - } - } - }; - match *terr { - TypeError::Sorts(ref exp_found) => { - // if they are both "path types", there's a chance of ambiguity - // due to different versions of the same crate - match (&exp_found.expected.sty, &exp_found.found.sty) { - (&ty::TyEnum(ref exp_adt, _), &ty::TyEnum(ref found_adt, _)) | - (&ty::TyStruct(ref exp_adt, _), &ty::TyStruct(ref found_adt, _)) | - (&ty::TyEnum(ref exp_adt, _), &ty::TyStruct(ref found_adt, _)) | - (&ty::TyStruct(ref exp_adt, _), &ty::TyEnum(ref found_adt, _)) => { - report_path_match(err, exp_adt.did, found_adt.did); - }, - _ => () - } - }, - TypeError::Traits(ref exp_found) => { - report_path_match(err, exp_found.expected, exp_found.found); - }, - _ => () // FIXME(#22750) handle traits and stuff - } - } - - fn report_and_explain_type_error(&self, - trace: TypeTrace<'tcx>, - terr: &TypeError<'tcx>) - -> DiagnosticBuilder<'tcx> { - let span = trace.origin.span(); - let mut err = self.report_type_error(trace, terr); - self.tcx.note_and_explain_type_err(&mut err, terr, span); - err - } - - /// Returns a string of the form "expected `{}`, found `{}`", or None if this is a derived - /// error. - fn values_str(&self, values: &ValuePairs<'tcx>) -> Option { - match *values { - infer::Types(ref exp_found) => self.expected_found_str(exp_found), - infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found), - infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found) - } - } - - fn expected_found_str + TypeFoldable<'tcx>>( - &self, - exp_found: &ty::error::ExpectedFound) - -> Option - { - let expected = exp_found.expected.resolve(self); - if expected.references_error() { - return None; - } - - let found = exp_found.found.resolve(self); - if found.references_error() { - return None; - } - - Some(format!("expected `{}`, found `{}`", - expected, - found)) - } - - fn report_generic_bound_failure(&self, - origin: SubregionOrigin<'tcx>, - bound_kind: GenericKind<'tcx>, - sub: Region) - { - // FIXME: it would be better to report the first error message - // with the span of the parameter itself, rather than the span - // where the error was detected. But that span is not readily - // accessible. - - let labeled_user_string = match bound_kind { - GenericKind::Param(ref p) => - format!("the parameter type `{}`", p), - GenericKind::Projection(ref p) => - format!("the associated type `{}`", p), - }; - - let mut err = match sub { - ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => { - // Does the required lifetime have a nice name we can print? - let mut err = struct_span_err!(self.tcx.sess, - origin.span(), - E0309, - "{} may not live long enough", - labeled_user_string); - err.fileline_help(origin.span(), - &format!("consider adding an explicit lifetime bound `{}: {}`...", - bound_kind, - sub)); - err - } - - ty::ReStatic => { - // Does the required lifetime have a nice name we can print? - let mut err = struct_span_err!(self.tcx.sess, - origin.span(), - E0310, - "{} may not live long enough", - labeled_user_string); - err.fileline_help(origin.span(), - &format!("consider adding an explicit lifetime \ - bound `{}: 'static`...", - bound_kind)); - err - } - - _ => { - // If not, be less specific. - let mut err = struct_span_err!(self.tcx.sess, - origin.span(), - E0311, - "{} may not live long enough", - labeled_user_string); - err.fileline_help(origin.span(), - &format!("consider adding an explicit lifetime bound for `{}`", - bound_kind)); - self.tcx.note_and_explain_region( - &mut err, - &format!("{} must be valid for ", labeled_user_string), - sub, - "..."); - err - } - }; - - self.note_region_origin(&mut err, &origin); - err.emit(); - } - - fn report_concrete_failure(&self, - origin: SubregionOrigin<'tcx>, - sub: Region, - sup: Region) - -> DiagnosticBuilder<'tcx> { - match origin { - infer::Subtype(trace) => { - let terr = TypeError::RegionsDoesNotOutlive(sup, sub); - self.report_and_explain_type_error(trace, &terr) - } - infer::Reborrow(span) => { - let mut err = struct_span_err!(self.tcx.sess, span, E0312, - "lifetime of reference outlines \ - lifetime of borrowed content..."); - self.tcx.note_and_explain_region(&mut err, - "...the reference is valid for ", - sub, - "..."); - self.tcx.note_and_explain_region(&mut err, - "...but the borrowed content is only valid for ", - sup, - ""); - err - } - infer::ReborrowUpvar(span, ref upvar_id) => { - let mut err = struct_span_err!(self.tcx.sess, span, E0313, - "lifetime of borrowed pointer outlives \ - lifetime of captured variable `{}`...", - self.tcx.local_var_name_str(upvar_id.var_id)); - self.tcx.note_and_explain_region(&mut err, - "...the borrowed pointer is valid for ", - sub, - "..."); - self.tcx.note_and_explain_region(&mut err, - &format!("...but `{}` is only valid for ", - self.tcx.local_var_name_str(upvar_id.var_id)), - sup, - ""); - err - } - infer::InfStackClosure(span) => { - let mut err = struct_span_err!(self.tcx.sess, span, E0314, - "closure outlives stack frame"); - self.tcx.note_and_explain_region(&mut err, - "...the closure must be valid for ", - sub, - "..."); - self.tcx.note_and_explain_region(&mut err, - "...but the closure's stack frame is only valid for ", - sup, - ""); - err - } - infer::InvokeClosure(span) => { - let mut err = struct_span_err!(self.tcx.sess, span, E0315, - "cannot invoke closure outside of its lifetime"); - self.tcx.note_and_explain_region(&mut err, - "the closure is only valid for ", - sup, - ""); - err - } - infer::DerefPointer(span) => { - let mut err = struct_span_err!(self.tcx.sess, span, E0473, - "dereference of reference outside its lifetime"); - self.tcx.note_and_explain_region(&mut err, - "the reference is only valid for ", - sup, - ""); - err - } - infer::FreeVariable(span, id) => { - let mut err = struct_span_err!(self.tcx.sess, span, E0474, - "captured variable `{}` does not outlive the enclosing closure", - self.tcx.local_var_name_str(id)); - self.tcx.note_and_explain_region(&mut err, - "captured variable is valid for ", - sup, - ""); - self.tcx.note_and_explain_region(&mut err, - "closure is valid for ", - sub, - ""); - err - } - infer::IndexSlice(span) => { - let mut err = struct_span_err!(self.tcx.sess, span, E0475, - "index of slice outside its lifetime"); - self.tcx.note_and_explain_region(&mut err, - "the slice is only valid for ", - sup, - ""); - err - } - infer::RelateObjectBound(span) => { - let mut err = struct_span_err!(self.tcx.sess, span, E0476, - "lifetime of the source pointer does not outlive \ - lifetime bound of the object type"); - self.tcx.note_and_explain_region(&mut err, - "object type is valid for ", - sub, - ""); - self.tcx.note_and_explain_region(&mut err, - "source pointer is only valid for ", - sup, - ""); - err - } - infer::RelateParamBound(span, ty) => { - let mut err = struct_span_err!(self.tcx.sess, span, E0477, - "the type `{}` does not fulfill the required lifetime", - self.ty_to_string(ty)); - self.tcx.note_and_explain_region(&mut err, - "type must outlive ", - sub, - ""); - err - } - infer::RelateRegionParamBound(span) => { - let mut err = struct_span_err!(self.tcx.sess, span, E0478, - "lifetime bound not satisfied"); - self.tcx.note_and_explain_region(&mut err, - "lifetime parameter instantiated with ", - sup, - ""); - self.tcx.note_and_explain_region(&mut err, - "but lifetime parameter must outlive ", - sub, - ""); - err - } - infer::RelateDefaultParamBound(span, ty) => { - let mut err = struct_span_err!(self.tcx.sess, span, E0479, - "the type `{}` (provided as the value of \ - a type parameter) is not valid at this point", - self.ty_to_string(ty)); - self.tcx.note_and_explain_region(&mut err, - "type must outlive ", - sub, - ""); - err - } - infer::CallRcvr(span) => { - let mut err = struct_span_err!(self.tcx.sess, span, E0480, - "lifetime of method receiver does not outlive \ - the method call"); - self.tcx.note_and_explain_region(&mut err, - "the receiver is only valid for ", - sup, - ""); - err - } - infer::CallArg(span) => { - let mut err = struct_span_err!(self.tcx.sess, span, E0481, - "lifetime of function argument does not outlive \ - the function call"); - self.tcx.note_and_explain_region(&mut err, - "the function argument is only valid for ", - sup, - ""); - err - } - infer::CallReturn(span) => { - let mut err = struct_span_err!(self.tcx.sess, span, E0482, - "lifetime of return value does not outlive \ - the function call"); - self.tcx.note_and_explain_region(&mut err, - "the return value is only valid for ", - sup, - ""); - err - } - infer::Operand(span) => { - let mut err = struct_span_err!(self.tcx.sess, span, E0483, - "lifetime of operand does not outlive \ - the operation"); - self.tcx.note_and_explain_region(&mut err, - "the operand is only valid for ", - sup, - ""); - err - } - infer::AddrOf(span) => { - let mut err = struct_span_err!(self.tcx.sess, span, E0484, - "reference is not valid at the time of borrow"); - self.tcx.note_and_explain_region(&mut err, - "the borrow is only valid for ", - sup, - ""); - err - } - infer::AutoBorrow(span) => { - let mut err = struct_span_err!(self.tcx.sess, span, E0485, - "automatically reference is not valid \ - at the time of borrow"); - self.tcx.note_and_explain_region(&mut err, - "the automatic borrow is only valid for ", - sup, - ""); - err - } - infer::ExprTypeIsNotInScope(t, span) => { - let mut err = struct_span_err!(self.tcx.sess, span, E0486, - "type of expression contains references \ - that are not valid during the expression: `{}`", - self.ty_to_string(t)); - self.tcx.note_and_explain_region(&mut err, - "type is only valid for ", - sup, - ""); - err - } - infer::SafeDestructor(span) => { - let mut err = struct_span_err!(self.tcx.sess, span, E0487, - "unsafe use of destructor: destructor might be called \ - while references are dead"); - // FIXME (22171): terms "super/subregion" are suboptimal - self.tcx.note_and_explain_region(&mut err, - "superregion: ", - sup, - ""); - self.tcx.note_and_explain_region(&mut err, - "subregion: ", - sub, - ""); - err - } - infer::BindingTypeIsNotValidAtDecl(span) => { - let mut err = struct_span_err!(self.tcx.sess, span, E0488, - "lifetime of variable does not enclose its declaration"); - self.tcx.note_and_explain_region(&mut err, - "the variable is only valid for ", - sup, - ""); - err - } - infer::ParameterInScope(_, span) => { - let mut err = struct_span_err!(self.tcx.sess, span, E0489, - "type/lifetime parameter not in scope here"); - self.tcx.note_and_explain_region(&mut err, - "the parameter is only valid for ", - sub, - ""); - err - } - infer::DataBorrowed(ty, span) => { - let mut err = struct_span_err!(self.tcx.sess, span, E0490, - "a value of type `{}` is borrowed for too long", - self.ty_to_string(ty)); - self.tcx.note_and_explain_region(&mut err, "the type is valid for ", sub, ""); - self.tcx.note_and_explain_region(&mut err, "but the borrow lasts for ", sup, ""); - err - } - infer::ReferenceOutlivesReferent(ty, span) => { - let mut err = struct_span_err!(self.tcx.sess, span, E0491, - "in type `{}`, reference has a longer lifetime \ - than the data it references", - self.ty_to_string(ty)); - self.tcx.note_and_explain_region(&mut err, - "the pointer is valid for ", - sub, - ""); - self.tcx.note_and_explain_region(&mut err, - "but the referenced data is only valid for ", - sup, - ""); - err - } - } - } - - fn report_sub_sup_conflict(&self, - var_origin: RegionVariableOrigin, - sub_origin: SubregionOrigin<'tcx>, - sub_region: Region, - sup_origin: SubregionOrigin<'tcx>, - sup_region: Region) { - let mut err = self.report_inference_failure(var_origin); - - self.tcx.note_and_explain_region(&mut err, - "first, the lifetime cannot outlive ", - sup_region, - "..."); - - self.note_region_origin(&mut err, &sup_origin); - - self.tcx.note_and_explain_region(&mut err, - "but, the lifetime must be valid for ", - sub_region, - "..."); - - self.note_region_origin(&mut err, &sub_origin); - err.emit(); - } - - fn report_processed_errors(&self, - origins: &[ProcessedErrorOrigin<'tcx>], - same_regions: &[SameRegions]) { - for (i, origin) in origins.iter().enumerate() { - let mut err = match *origin { - ProcessedErrorOrigin::VariableFailure(ref var_origin) => - self.report_inference_failure(var_origin.clone()), - ProcessedErrorOrigin::ConcreteFailure(ref sr_origin, sub, sup) => - self.report_concrete_failure(sr_origin.clone(), sub, sup), - }; - - // attach the suggestion to the last such error - if i == origins.len() - 1 { - self.give_suggestion(&mut err, same_regions); - } - - err.emit(); - } - } - - fn give_suggestion(&self, err: &mut DiagnosticBuilder, same_regions: &[SameRegions]) { - let scope_id = same_regions[0].scope_id; - let parent = self.tcx.map.get_parent(scope_id); - let parent_node = self.tcx.map.find(parent); - let taken = lifetimes_in_scope(self.tcx, scope_id); - let life_giver = LifeGiver::with_taken(&taken[..]); - let node_inner = match parent_node { - Some(ref node) => match *node { - ast_map::NodeItem(ref item) => { - match item.node { - hir::ItemFn(ref fn_decl, unsafety, constness, _, ref gen, _) => { - Some((fn_decl, gen, unsafety, constness, - item.name, None, item.span)) - }, - _ => None - } - } - ast_map::NodeImplItem(item) => { - match item.node { - hir::ImplItemKind::Method(ref sig, _) => { - Some((&sig.decl, - &sig.generics, - sig.unsafety, - sig.constness, - item.name, - Some(&sig.explicit_self.node), - item.span)) - } - _ => None, - } - }, - ast_map::NodeTraitItem(item) => { - match item.node { - hir::MethodTraitItem(ref sig, Some(_)) => { - Some((&sig.decl, - &sig.generics, - sig.unsafety, - sig.constness, - item.name, - Some(&sig.explicit_self.node), - item.span)) - } - _ => None - } - } - _ => None - }, - None => None - }; - let (fn_decl, generics, unsafety, constness, name, expl_self, span) - = node_inner.expect("expect item fn"); - let rebuilder = Rebuilder::new(self.tcx, fn_decl, expl_self, - generics, same_regions, &life_giver); - let (fn_decl, expl_self, generics) = rebuilder.rebuild(); - self.give_expl_lifetime_param(err, &fn_decl, unsafety, constness, name, - expl_self.as_ref(), &generics, span); - } -} - -struct RebuildPathInfo<'a> { - path: &'a hir::Path, - // indexes to insert lifetime on path.lifetimes - indexes: Vec, - // number of lifetimes we expect to see on the type referred by `path` - // (e.g., expected=1 for struct Foo<'a>) - expected: u32, - anon_nums: &'a HashSet, - region_names: &'a HashSet -} - -struct Rebuilder<'a, 'tcx: 'a> { - tcx: &'a TyCtxt<'tcx>, - fn_decl: &'a hir::FnDecl, - expl_self_opt: Option<&'a hir::ExplicitSelf_>, - generics: &'a hir::Generics, - same_regions: &'a [SameRegions], - life_giver: &'a LifeGiver, - cur_anon: Cell, - inserted_anons: RefCell>, -} - -enum FreshOrKept { - Fresh, - Kept -} - -impl<'a, 'tcx> Rebuilder<'a, 'tcx> { - fn new(tcx: &'a TyCtxt<'tcx>, - fn_decl: &'a hir::FnDecl, - expl_self_opt: Option<&'a hir::ExplicitSelf_>, - generics: &'a hir::Generics, - same_regions: &'a [SameRegions], - life_giver: &'a LifeGiver) - -> Rebuilder<'a, 'tcx> { - Rebuilder { - tcx: tcx, - fn_decl: fn_decl, - expl_self_opt: expl_self_opt, - generics: generics, - same_regions: same_regions, - life_giver: life_giver, - cur_anon: Cell::new(0), - inserted_anons: RefCell::new(HashSet::new()), - } - } - - fn rebuild(&self) - -> (hir::FnDecl, Option, hir::Generics) { - let mut expl_self_opt = self.expl_self_opt.cloned(); - let mut inputs = self.fn_decl.inputs.clone(); - let mut output = self.fn_decl.output.clone(); - let mut ty_params = self.generics.ty_params.clone(); - let where_clause = self.generics.where_clause.clone(); - let mut kept_lifetimes = HashSet::new(); - for sr in self.same_regions { - self.cur_anon.set(0); - self.offset_cur_anon(); - let (anon_nums, region_names) = - self.extract_anon_nums_and_names(sr); - let (lifetime, fresh_or_kept) = self.pick_lifetime(®ion_names); - match fresh_or_kept { - Kept => { kept_lifetimes.insert(lifetime.name); } - _ => () - } - expl_self_opt = self.rebuild_expl_self(expl_self_opt, lifetime, - &anon_nums, ®ion_names); - inputs = self.rebuild_args_ty(&inputs[..], lifetime, - &anon_nums, ®ion_names); - output = self.rebuild_output(&output, lifetime, &anon_nums, ®ion_names); - ty_params = self.rebuild_ty_params(ty_params, lifetime, - ®ion_names); - } - let fresh_lifetimes = self.life_giver.get_generated_lifetimes(); - let all_region_names = self.extract_all_region_names(); - let generics = self.rebuild_generics(self.generics, - &fresh_lifetimes, - &kept_lifetimes, - &all_region_names, - ty_params, - where_clause); - let new_fn_decl = hir::FnDecl { - inputs: inputs, - output: output, - variadic: self.fn_decl.variadic - }; - (new_fn_decl, expl_self_opt, generics) - } - - fn pick_lifetime(&self, - region_names: &HashSet) - -> (hir::Lifetime, FreshOrKept) { - if !region_names.is_empty() { - // It's not necessary to convert the set of region names to a - // vector of string and then sort them. However, it makes the - // choice of lifetime name deterministic and thus easier to test. - let mut names = Vec::new(); - for rn in region_names { - let lt_name = rn.to_string(); - names.push(lt_name); - } - names.sort(); - let name = token::intern(&names[0]); - return (name_to_dummy_lifetime(name), Kept); - } - return (self.life_giver.give_lifetime(), Fresh); - } - - fn extract_anon_nums_and_names(&self, same_regions: &SameRegions) - -> (HashSet, HashSet) { - let mut anon_nums = HashSet::new(); - let mut region_names = HashSet::new(); - for br in &same_regions.regions { - match *br { - ty::BrAnon(i) => { - anon_nums.insert(i); - } - ty::BrNamed(_, name) => { - region_names.insert(name); - } - _ => () - } - } - (anon_nums, region_names) - } - - fn extract_all_region_names(&self) -> HashSet { - let mut all_region_names = HashSet::new(); - for sr in self.same_regions { - for br in &sr.regions { - match *br { - ty::BrNamed(_, name) => { - all_region_names.insert(name); - } - _ => () - } - } - } - all_region_names - } - - fn inc_cur_anon(&self, n: u32) { - let anon = self.cur_anon.get(); - self.cur_anon.set(anon+n); - } - - fn offset_cur_anon(&self) { - let mut anon = self.cur_anon.get(); - while self.inserted_anons.borrow().contains(&anon) { - anon += 1; - } - self.cur_anon.set(anon); - } - - fn inc_and_offset_cur_anon(&self, n: u32) { - self.inc_cur_anon(n); - self.offset_cur_anon(); - } - - fn track_anon(&self, anon: u32) { - self.inserted_anons.borrow_mut().insert(anon); - } - - fn rebuild_ty_params(&self, - ty_params: hir::HirVec, - lifetime: hir::Lifetime, - region_names: &HashSet) - -> hir::HirVec { - ty_params.iter().map(|ty_param| { - let bounds = self.rebuild_ty_param_bounds(ty_param.bounds.clone(), - lifetime, - region_names); - hir::TyParam { - name: ty_param.name, - id: ty_param.id, - bounds: bounds, - default: ty_param.default.clone(), - span: ty_param.span, - } - }).collect() - } - - fn rebuild_ty_param_bounds(&self, - ty_param_bounds: hir::TyParamBounds, - lifetime: hir::Lifetime, - region_names: &HashSet) - -> hir::TyParamBounds { - ty_param_bounds.iter().map(|tpb| { - match tpb { - &hir::RegionTyParamBound(lt) => { - // FIXME -- it's unclear whether I'm supposed to - // substitute lifetime here. I suspect we need to - // be passing down a map. - hir::RegionTyParamBound(lt) - } - &hir::TraitTyParamBound(ref poly_tr, modifier) => { - let tr = &poly_tr.trait_ref; - let last_seg = tr.path.segments.last().unwrap(); - let mut insert = Vec::new(); - let lifetimes = last_seg.parameters.lifetimes(); - for (i, lt) in lifetimes.iter().enumerate() { - if region_names.contains(<.name) { - insert.push(i as u32); - } - } - let rebuild_info = RebuildPathInfo { - path: &tr.path, - indexes: insert, - expected: lifetimes.len() as u32, - anon_nums: &HashSet::new(), - region_names: region_names - }; - let new_path = self.rebuild_path(rebuild_info, lifetime); - hir::TraitTyParamBound(hir::PolyTraitRef { - bound_lifetimes: poly_tr.bound_lifetimes.clone(), - trait_ref: hir::TraitRef { - path: new_path, - ref_id: tr.ref_id, - }, - span: poly_tr.span, - }, modifier) - } - } - }).collect() - } - - fn rebuild_expl_self(&self, - expl_self_opt: Option, - lifetime: hir::Lifetime, - anon_nums: &HashSet, - region_names: &HashSet) - -> Option { - match expl_self_opt { - Some(ref expl_self) => match *expl_self { - hir::SelfRegion(lt_opt, muta, id) => match lt_opt { - Some(lt) => if region_names.contains(<.name) { - return Some(hir::SelfRegion(Some(lifetime), muta, id)); - }, - None => { - let anon = self.cur_anon.get(); - self.inc_and_offset_cur_anon(1); - if anon_nums.contains(&anon) { - self.track_anon(anon); - return Some(hir::SelfRegion(Some(lifetime), muta, id)); - } - } - }, - _ => () - }, - None => () - } - expl_self_opt - } - - fn rebuild_generics(&self, - generics: &hir::Generics, - add: &Vec, - keep: &HashSet, - remove: &HashSet, - ty_params: hir::HirVec, - where_clause: hir::WhereClause) - -> hir::Generics { - let mut lifetimes = Vec::new(); - for lt in add { - lifetimes.push(hir::LifetimeDef { lifetime: *lt, - bounds: hir::HirVec::new() }); - } - for lt in &generics.lifetimes { - if keep.contains(<.lifetime.name) || - !remove.contains(<.lifetime.name) { - lifetimes.push((*lt).clone()); - } - } - hir::Generics { - lifetimes: lifetimes.into(), - ty_params: ty_params, - where_clause: where_clause, - } - } - - fn rebuild_args_ty(&self, - inputs: &[hir::Arg], - lifetime: hir::Lifetime, - anon_nums: &HashSet, - region_names: &HashSet) - -> hir::HirVec { - let mut new_inputs = Vec::new(); - for arg in inputs { - let new_ty = self.rebuild_arg_ty_or_output(&arg.ty, lifetime, - anon_nums, region_names); - let possibly_new_arg = hir::Arg { - ty: new_ty, - pat: arg.pat.clone(), - id: arg.id - }; - new_inputs.push(possibly_new_arg); - } - new_inputs.into() - } - - fn rebuild_output(&self, ty: &hir::FunctionRetTy, - lifetime: hir::Lifetime, - anon_nums: &HashSet, - region_names: &HashSet) -> hir::FunctionRetTy { - match *ty { - hir::Return(ref ret_ty) => hir::Return( - self.rebuild_arg_ty_or_output(&ret_ty, lifetime, anon_nums, region_names) - ), - hir::DefaultReturn(span) => hir::DefaultReturn(span), - hir::NoReturn(span) => hir::NoReturn(span) - } - } - - fn rebuild_arg_ty_or_output(&self, - ty: &hir::Ty, - lifetime: hir::Lifetime, - anon_nums: &HashSet, - region_names: &HashSet) - -> P { - let mut new_ty = P(ty.clone()); - let mut ty_queue = vec!(ty); - while !ty_queue.is_empty() { - let cur_ty = ty_queue.remove(0); - match cur_ty.node { - hir::TyRptr(lt_opt, ref mut_ty) => { - let rebuild = match lt_opt { - Some(lt) => region_names.contains(<.name), - None => { - let anon = self.cur_anon.get(); - let rebuild = anon_nums.contains(&anon); - if rebuild { - self.track_anon(anon); - } - self.inc_and_offset_cur_anon(1); - rebuild - } - }; - if rebuild { - let to = hir::Ty { - id: cur_ty.id, - node: hir::TyRptr(Some(lifetime), mut_ty.clone()), - span: cur_ty.span - }; - new_ty = self.rebuild_ty(new_ty, P(to)); - } - ty_queue.push(&mut_ty.ty); - } - hir::TyPath(ref maybe_qself, ref path) => { - let a_def = match self.tcx.def_map.borrow().get(&cur_ty.id) { - None => { - self.tcx - .sess - .fatal(&format!( - "unbound path {}", - pprust::path_to_string(path))) - } - Some(d) => d.full_def() - }; - match a_def { - Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) => { - let generics = self.tcx.lookup_item_type(did).generics; - - let expected = - generics.regions.len(subst::TypeSpace) as u32; - let lifetimes = - path.segments.last().unwrap().parameters.lifetimes(); - let mut insert = Vec::new(); - if lifetimes.is_empty() { - let anon = self.cur_anon.get(); - for (i, a) in (anon..anon+expected).enumerate() { - if anon_nums.contains(&a) { - insert.push(i as u32); - } - self.track_anon(a); - } - self.inc_and_offset_cur_anon(expected); - } else { - for (i, lt) in lifetimes.iter().enumerate() { - if region_names.contains(<.name) { - insert.push(i as u32); - } - } - } - let rebuild_info = RebuildPathInfo { - path: path, - indexes: insert, - expected: expected, - anon_nums: anon_nums, - region_names: region_names - }; - let new_path = self.rebuild_path(rebuild_info, lifetime); - let qself = maybe_qself.as_ref().map(|qself| { - hir::QSelf { - ty: self.rebuild_arg_ty_or_output(&qself.ty, lifetime, - anon_nums, region_names), - position: qself.position - } - }); - let to = hir::Ty { - id: cur_ty.id, - node: hir::TyPath(qself, new_path), - span: cur_ty.span - }; - new_ty = self.rebuild_ty(new_ty, P(to)); - } - _ => () - } - } - - hir::TyPtr(ref mut_ty) => { - ty_queue.push(&mut_ty.ty); - } - hir::TyVec(ref ty) | - hir::TyFixedLengthVec(ref ty, _) => { - ty_queue.push(&ty); - } - hir::TyTup(ref tys) => ty_queue.extend(tys.iter().map(|ty| &**ty)), - _ => {} - } - } - new_ty - } - - fn rebuild_ty(&self, - from: P, - to: P) - -> P { - - fn build_to(from: P, - to: &mut Option>) - -> P { - if Some(from.id) == to.as_ref().map(|ty| ty.id) { - return to.take().expect("`to` type found more than once during rebuild"); - } - from.map(|hir::Ty {id, node, span}| { - let new_node = match node { - hir::TyRptr(lifetime, mut_ty) => { - hir::TyRptr(lifetime, hir::MutTy { - mutbl: mut_ty.mutbl, - ty: build_to(mut_ty.ty, to), - }) - } - hir::TyPtr(mut_ty) => { - hir::TyPtr(hir::MutTy { - mutbl: mut_ty.mutbl, - ty: build_to(mut_ty.ty, to), - }) - } - hir::TyVec(ty) => hir::TyVec(build_to(ty, to)), - hir::TyFixedLengthVec(ty, e) => { - hir::TyFixedLengthVec(build_to(ty, to), e) - } - hir::TyTup(tys) => { - hir::TyTup(tys.into_iter().map(|ty| build_to(ty, to)).collect()) - } - other => other - }; - hir::Ty { id: id, node: new_node, span: span } - }) - } - - build_to(from, &mut Some(to)) - } - - fn rebuild_path(&self, - rebuild_info: RebuildPathInfo, - lifetime: hir::Lifetime) - -> hir::Path - { - let RebuildPathInfo { - path, - indexes, - expected, - anon_nums, - region_names, - } = rebuild_info; - - let last_seg = path.segments.last().unwrap(); - let new_parameters = match last_seg.parameters { - hir::ParenthesizedParameters(..) => { - last_seg.parameters.clone() - } - - hir::AngleBracketedParameters(ref data) => { - let mut new_lts = Vec::new(); - if data.lifetimes.is_empty() { - // traverse once to see if there's a need to insert lifetime - let need_insert = (0..expected).any(|i| { - indexes.contains(&i) - }); - if need_insert { - for i in 0..expected { - if indexes.contains(&i) { - new_lts.push(lifetime); - } else { - new_lts.push(self.life_giver.give_lifetime()); - } - } - } - } else { - for (i, lt) in data.lifetimes.iter().enumerate() { - if indexes.contains(&(i as u32)) { - new_lts.push(lifetime); - } else { - new_lts.push(*lt); - } - } - } - let new_types = data.types.iter().map(|t| { - self.rebuild_arg_ty_or_output(&t, lifetime, anon_nums, region_names) - }).collect(); - let new_bindings = data.bindings.iter().map(|b| { - hir::TypeBinding { - id: b.id, - name: b.name, - ty: self.rebuild_arg_ty_or_output(&b.ty, - lifetime, - anon_nums, - region_names), - span: b.span - } - }).collect(); - hir::AngleBracketedParameters(hir::AngleBracketedParameterData { - lifetimes: new_lts.into(), - types: new_types, - bindings: new_bindings, - }) - } - }; - let new_seg = hir::PathSegment { - identifier: last_seg.identifier, - parameters: new_parameters - }; - let mut new_segs = Vec::new(); - new_segs.extend_from_slice(path.segments.split_last().unwrap().1); - new_segs.push(new_seg); - hir::Path { - span: path.span, - global: path.global, - segments: new_segs.into() - } - } -} - -impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { - fn give_expl_lifetime_param(&self, - err: &mut DiagnosticBuilder, - decl: &hir::FnDecl, - unsafety: hir::Unsafety, - constness: hir::Constness, - name: ast::Name, - opt_explicit_self: Option<&hir::ExplicitSelf_>, - generics: &hir::Generics, - span: Span) { - let suggested_fn = pprust::fun_to_string(decl, unsafety, constness, name, - opt_explicit_self, generics); - let msg = format!("consider using an explicit lifetime \ - parameter as shown: {}", suggested_fn); - err.span_help(span, &msg[..]); - } - - fn report_inference_failure(&self, - var_origin: RegionVariableOrigin) - -> DiagnosticBuilder<'tcx> { - let br_string = |br: ty::BoundRegion| { - let mut s = br.to_string(); - if !s.is_empty() { - s.push_str(" "); - } - s - }; - let var_description = match var_origin { - infer::MiscVariable(_) => "".to_string(), - infer::PatternRegion(_) => " for pattern".to_string(), - infer::AddrOfRegion(_) => " for borrow expression".to_string(), - infer::Autoref(_) => " for autoref".to_string(), - infer::Coercion(_) => " for automatic coercion".to_string(), - infer::LateBoundRegion(_, br, infer::FnCall) => { - format!(" for lifetime parameter {}in function call", - br_string(br)) - } - infer::LateBoundRegion(_, br, infer::HigherRankedType) => { - format!(" for lifetime parameter {}in generic type", br_string(br)) - } - infer::LateBoundRegion(_, br, infer::AssocTypeProjection(type_name)) => { - format!(" for lifetime parameter {}in trait containing associated type `{}`", - br_string(br), type_name) - } - infer::EarlyBoundRegion(_, name) => { - format!(" for lifetime parameter `{}`", - name) - } - infer::BoundRegionInCoherence(name) => { - format!(" for lifetime parameter `{}` in coherence check", - name) - } - infer::UpvarRegion(ref upvar_id, _) => { - format!(" for capture of `{}` by closure", - self.tcx.local_var_name_str(upvar_id.var_id).to_string()) - } - }; - - struct_span_err!(self.tcx.sess, var_origin.span(), E0495, - "cannot infer an appropriate lifetime{} \ - due to conflicting requirements", - var_description) - } - - fn note_region_origin(&self, err: &mut DiagnosticBuilder, origin: &SubregionOrigin<'tcx>) { - match *origin { - infer::Subtype(ref trace) => { - let desc = match trace.origin { - TypeOrigin::Misc(_) => { - "types are compatible" - } - TypeOrigin::MethodCompatCheck(_) => { - "method type is compatible with trait" - } - TypeOrigin::ExprAssignable(_) => { - "expression is assignable" - } - TypeOrigin::RelateTraitRefs(_) => { - "traits are compatible" - } - TypeOrigin::RelateSelfType(_) => { - "self type matches impl self type" - } - TypeOrigin::RelateOutputImplTypes(_) => { - "trait type parameters matches those \ - specified on the impl" - } - TypeOrigin::MatchExpressionArm(_, _, _) => { - "match arms have compatible types" - } - TypeOrigin::IfExpression(_) => { - "if and else have compatible types" - } - TypeOrigin::IfExpressionWithNoElse(_) => { - "if may be missing an else clause" - } - TypeOrigin::RangeExpression(_) => { - "start and end of range have compatible types" - } - TypeOrigin::EquatePredicate(_) => { - "equality where clause is satisfied" - } - }; - - match self.values_str(&trace.values) { - Some(values_str) => { - err.span_note( - trace.origin.span(), - &format!("...so that {} ({})", - desc, values_str)); - } - None => { - // Really should avoid printing this error at - // all, since it is derived, but that would - // require more refactoring than I feel like - // doing right now. - nmatsakis - err.span_note( - trace.origin.span(), - &format!("...so that {}", desc)); - } - } - } - infer::Reborrow(span) => { - err.span_note( - span, - "...so that reference does not outlive \ - borrowed content"); - } - infer::ReborrowUpvar(span, ref upvar_id) => { - err.span_note( - span, - &format!( - "...so that closure can access `{}`", - self.tcx.local_var_name_str(upvar_id.var_id) - .to_string())); - } - infer::InfStackClosure(span) => { - err.span_note( - span, - "...so that closure does not outlive its stack frame"); - } - infer::InvokeClosure(span) => { - err.span_note( - span, - "...so that closure is not invoked outside its lifetime"); - } - infer::DerefPointer(span) => { - err.span_note( - span, - "...so that pointer is not dereferenced \ - outside its lifetime"); - } - infer::FreeVariable(span, id) => { - err.span_note( - span, - &format!("...so that captured variable `{}` \ - does not outlive the enclosing closure", - self.tcx.local_var_name_str(id))); - } - infer::IndexSlice(span) => { - err.span_note( - span, - "...so that slice is not indexed outside the lifetime"); - } - infer::RelateObjectBound(span) => { - err.span_note( - span, - "...so that it can be closed over into an object"); - } - infer::CallRcvr(span) => { - err.span_note( - span, - "...so that method receiver is valid for the method call"); - } - infer::CallArg(span) => { - err.span_note( - span, - "...so that argument is valid for the call"); - } - infer::CallReturn(span) => { - err.span_note( - span, - "...so that return value is valid for the call"); - } - infer::Operand(span) => { - err.span_note( - span, - "...so that operand is valid for operation"); - } - infer::AddrOf(span) => { - err.span_note( - span, - "...so that reference is valid \ - at the time of borrow"); - } - infer::AutoBorrow(span) => { - err.span_note( - span, - "...so that auto-reference is valid \ - at the time of borrow"); - } - infer::ExprTypeIsNotInScope(t, span) => { - err.span_note( - span, - &format!("...so type `{}` of expression is valid during the \ - expression", - self.ty_to_string(t))); - } - infer::BindingTypeIsNotValidAtDecl(span) => { - err.span_note( - span, - "...so that variable is valid at time of its declaration"); - } - infer::ParameterInScope(_, span) => { - err.span_note( - span, - "...so that a type/lifetime parameter is in scope here"); - } - infer::DataBorrowed(ty, span) => { - err.span_note( - span, - &format!("...so that the type `{}` is not borrowed for too long", - self.ty_to_string(ty))); - } - infer::ReferenceOutlivesReferent(ty, span) => { - err.span_note( - span, - &format!("...so that the reference type `{}` \ - does not outlive the data it points at", - self.ty_to_string(ty))); - } - infer::RelateParamBound(span, t) => { - err.span_note( - span, - &format!("...so that the type `{}` \ - will meet its required lifetime bounds", - self.ty_to_string(t))); - } - infer::RelateDefaultParamBound(span, t) => { - err.span_note( - span, - &format!("...so that type parameter \ - instantiated with `{}`, \ - will meet its declared lifetime bounds", - self.ty_to_string(t))); - } - infer::RelateRegionParamBound(span) => { - err.span_note( - span, - "...so that the declared lifetime parameter bounds \ - are satisfied"); - } - infer::SafeDestructor(span) => { - err.span_note( - span, - "...so that references are valid when the destructor \ - runs"); - } - } - } -} - -pub trait Resolvable<'tcx> { - fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) -> Self; -} - -impl<'tcx> Resolvable<'tcx> for Ty<'tcx> { - fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) -> Ty<'tcx> { - infcx.resolve_type_vars_if_possible(self) - } -} - -impl<'tcx> Resolvable<'tcx> for ty::TraitRef<'tcx> { - fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) - -> ty::TraitRef<'tcx> { - infcx.resolve_type_vars_if_possible(self) - } -} - -impl<'tcx> Resolvable<'tcx> for ty::PolyTraitRef<'tcx> { - fn resolve<'a>(&self, - infcx: &InferCtxt<'a, 'tcx>) - -> ty::PolyTraitRef<'tcx> - { - infcx.resolve_type_vars_if_possible(self) - } -} - -fn lifetimes_in_scope(tcx: &TyCtxt, - scope_id: ast::NodeId) - -> Vec { - let mut taken = Vec::new(); - let parent = tcx.map.get_parent(scope_id); - let method_id_opt = match tcx.map.find(parent) { - Some(node) => match node { - ast_map::NodeItem(item) => match item.node { - hir::ItemFn(_, _, _, _, ref gen, _) => { - taken.extend_from_slice(&gen.lifetimes); - None - }, - _ => None - }, - ast_map::NodeImplItem(ii) => { - match ii.node { - hir::ImplItemKind::Method(ref sig, _) => { - taken.extend_from_slice(&sig.generics.lifetimes); - Some(ii.id) - } - _ => None, - } - } - _ => None - }, - None => None - }; - if method_id_opt.is_some() { - let method_id = method_id_opt.unwrap(); - let parent = tcx.map.get_parent(method_id); - match tcx.map.find(parent) { - Some(node) => match node { - ast_map::NodeItem(item) => match item.node { - hir::ItemImpl(_, _, ref gen, _, _, _) => { - taken.extend_from_slice(&gen.lifetimes); - } - _ => () - }, - _ => () - }, - None => () - } - } - return taken; -} - -// LifeGiver is responsible for generating fresh lifetime names -struct LifeGiver { - taken: HashSet, - counter: Cell, - generated: RefCell>, -} - -impl LifeGiver { - fn with_taken(taken: &[hir::LifetimeDef]) -> LifeGiver { - let mut taken_ = HashSet::new(); - for lt in taken { - let lt_name = lt.lifetime.name.to_string(); - taken_.insert(lt_name); - } - LifeGiver { - taken: taken_, - counter: Cell::new(0), - generated: RefCell::new(Vec::new()), - } - } - - fn inc_counter(&self) { - let c = self.counter.get(); - self.counter.set(c+1); - } - - fn give_lifetime(&self) -> hir::Lifetime { - let lifetime; - loop { - let mut s = String::from("'"); - s.push_str(&num_to_string(self.counter.get())); - if !self.taken.contains(&s) { - lifetime = name_to_dummy_lifetime(token::intern(&s[..])); - self.generated.borrow_mut().push(lifetime); - break; - } - self.inc_counter(); - } - self.inc_counter(); - return lifetime; - - // 0 .. 25 generates a .. z, 26 .. 51 generates aa .. zz, and so on - fn num_to_string(counter: usize) -> String { - let mut s = String::new(); - let (n, r) = (counter/26 + 1, counter % 26); - let letter: char = from_u32((r+97) as u32).unwrap(); - for _ in 0..n { - s.push(letter); - } - s - } - } - - fn get_generated_lifetimes(&self) -> Vec { - self.generated.borrow().clone() - } -} - -fn name_to_dummy_lifetime(name: ast::Name) -> hir::Lifetime { - hir::Lifetime { id: ast::DUMMY_NODE_ID, - span: codemap::DUMMY_SP, - name: name } -} diff --git a/src/librustc/middle/infer/freshen.rs b/src/librustc/middle/infer/freshen.rs deleted file mode 100644 index b0f6d45dc53..00000000000 --- a/src/librustc/middle/infer/freshen.rs +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright 2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Freshening is the process of replacing unknown variables with fresh types. The idea is that -//! the type, after freshening, contains no inference variables but instead contains either a -//! value for each variable or fresh "arbitrary" types wherever a variable would have been. -//! -//! Freshening is used primarily to get a good type for inserting into a cache. The result -//! summarizes what the type inferencer knows "so far". The primary place it is used right now is -//! in the trait matching algorithm, which needs to be able to cache whether an `impl` self type -//! matches some other type X -- *without* affecting `X`. That means if that if the type `X` is in -//! fact an unbound type variable, we want the match to be regarded as ambiguous, because depending -//! on what type that type variable is ultimately assigned, the match may or may not succeed. -//! -//! Note that you should be careful not to allow the output of freshening to leak to the user in -//! error messages or in any other form. Freshening is only really useful as an internal detail. -//! -//! __An important detail concerning regions.__ The freshener also replaces *all* regions with -//! 'static. The reason behind this is that, in general, we do not take region relationships into -//! account when making type-overloaded decisions. This is important because of the design of the -//! region inferencer, which is not based on unification but rather on accumulating and then -//! solving a set of constraints. In contrast, the type inferencer assigns a value to each type -//! variable only once, and it does so as soon as it can, so it is reasonable to ask what the type -//! inferencer knows "so far". - -use middle::ty::{self, Ty, TyCtxt, TypeFoldable}; -use middle::ty::fold::TypeFolder; -use std::collections::hash_map::{self, Entry}; - -use super::InferCtxt; -use super::unify_key::ToType; - -pub struct TypeFreshener<'a, 'tcx:'a> { - infcx: &'a InferCtxt<'a, 'tcx>, - freshen_count: u32, - freshen_map: hash_map::HashMap>, -} - -impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { - pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> TypeFreshener<'a, 'tcx> { - TypeFreshener { - infcx: infcx, - freshen_count: 0, - freshen_map: hash_map::HashMap::new(), - } - } - - fn freshen(&mut self, - opt_ty: Option>, - key: ty::InferTy, - freshener: F) - -> Ty<'tcx> where - F: FnOnce(u32) -> ty::InferTy, - { - match opt_ty { - Some(ty) => { return ty.fold_with(self); } - None => { } - } - - match self.freshen_map.entry(key) { - Entry::Occupied(entry) => *entry.get(), - Entry::Vacant(entry) => { - let index = self.freshen_count; - self.freshen_count += 1; - let t = self.infcx.tcx.mk_infer(freshener(index)); - entry.insert(t); - t - } - } - } -} - -impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { - fn tcx<'b>(&'b self) -> &'b TyCtxt<'tcx> { - self.infcx.tcx - } - - fn fold_region(&mut self, r: ty::Region) -> ty::Region { - match r { - ty::ReEarlyBound(..) | - ty::ReLateBound(..) => { - // leave bound regions alone - r - } - - ty::ReStatic | - ty::ReFree(_) | - ty::ReScope(_) | - ty::ReVar(_) | - ty::ReSkolemized(..) | - ty::ReEmpty => { - // replace all free regions with 'static - ty::ReStatic - } - } - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.needs_infer() && !t.has_erasable_regions() { - return t; - } - - let tcx = self.infcx.tcx; - - match t.sty { - ty::TyInfer(ty::TyVar(v)) => { - let opt_ty = self.infcx.type_variables.borrow_mut().probe(v); - self.freshen( - opt_ty, - ty::TyVar(v), - ty::FreshTy) - } - - ty::TyInfer(ty::IntVar(v)) => { - self.freshen( - self.infcx.int_unification_table.borrow_mut() - .probe(v) - .map(|v| v.to_type(tcx)), - ty::IntVar(v), - ty::FreshIntTy) - } - - ty::TyInfer(ty::FloatVar(v)) => { - self.freshen( - self.infcx.float_unification_table.borrow_mut() - .probe(v) - .map(|v| v.to_type(tcx)), - ty::FloatVar(v), - ty::FreshFloatTy) - } - - ty::TyInfer(ty::FreshTy(c)) | - ty::TyInfer(ty::FreshIntTy(c)) | - ty::TyInfer(ty::FreshFloatTy(c)) => { - if c >= self.freshen_count { - tcx.sess.bug( - &format!("Encountered a freshend type with id {} \ - but our counter is only at {}", - c, - self.freshen_count)); - } - t - } - - ty::TyBool | - ty::TyChar | - ty::TyInt(..) | - ty::TyUint(..) | - ty::TyFloat(..) | - ty::TyEnum(..) | - ty::TyBox(..) | - ty::TyStr | - ty::TyError | - ty::TyArray(..) | - ty::TySlice(..) | - ty::TyRawPtr(..) | - ty::TyRef(..) | - ty::TyFnDef(..) | - ty::TyFnPtr(_) | - ty::TyTrait(..) | - ty::TyStruct(..) | - ty::TyClosure(..) | - ty::TyTuple(..) | - ty::TyProjection(..) | - ty::TyParam(..) => { - t.super_fold_with(self) - } - } - } -} diff --git a/src/librustc/middle/infer/glb.rs b/src/librustc/middle/infer/glb.rs deleted file mode 100644 index 7779be896cf..00000000000 --- a/src/librustc/middle/infer/glb.rs +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::combine::CombineFields; -use super::higher_ranked::HigherRankedRelations; -use super::InferCtxt; -use super::lattice::{self, LatticeDir}; -use super::Subtype; - -use middle::ty::{self, Ty, TyCtxt}; -use middle::ty::relate::{Relate, RelateResult, TypeRelation}; - -/// "Greatest lower bound" (common subtype) -pub struct Glb<'a, 'tcx: 'a> { - fields: CombineFields<'a, 'tcx> -} - -impl<'a, 'tcx> Glb<'a, 'tcx> { - pub fn new(fields: CombineFields<'a, 'tcx>) -> Glb<'a, 'tcx> { - Glb { fields: fields } - } -} - -impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Glb<'a, 'tcx> { - fn tag(&self) -> &'static str { "Glb" } - - fn tcx(&self) -> &'a TyCtxt<'tcx> { self.fields.tcx() } - - fn a_is_expected(&self) -> bool { self.fields.a_is_expected } - - fn relate_with_variance>(&mut self, - variance: ty::Variance, - a: &T, - b: &T) - -> RelateResult<'tcx, T> - { - match variance { - ty::Invariant => self.fields.equate().relate(a, b), - ty::Covariant => self.relate(a, b), - ty::Bivariant => self.fields.bivariate().relate(a, b), - ty::Contravariant => self.fields.lub().relate(a, b), - } - } - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - lattice::super_lattice_tys(self, a, b) - } - - fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> { - debug!("{}.regions({:?}, {:?})", - self.tag(), - a, - b); - - let origin = Subtype(self.fields.trace.clone()); - Ok(self.fields.infcx.region_vars.glb_regions(origin, a, b)) - } - - fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) - -> RelateResult<'tcx, ty::Binder> - where T: Relate<'a, 'tcx> - { - self.fields.higher_ranked_glb(a, b) - } -} - -impl<'a, 'tcx> LatticeDir<'a,'tcx> for Glb<'a, 'tcx> { - fn infcx(&self) -> &'a InferCtxt<'a,'tcx> { - self.fields.infcx - } - - fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { - let mut sub = self.fields.sub(); - sub.relate(&v, &a)?; - sub.relate(&v, &b)?; - Ok(()) - } -} diff --git a/src/librustc/middle/infer/higher_ranked/README.md b/src/librustc/middle/infer/higher_ranked/README.md deleted file mode 100644 index 57665b6d939..00000000000 --- a/src/librustc/middle/infer/higher_ranked/README.md +++ /dev/null @@ -1,403 +0,0 @@ -# Skolemization and functions - -One of the trickiest and most subtle aspects of regions is dealing -with higher-ranked things which include bound region variables, such -as function types. I strongly suggest that if you want to understand -the situation, you read this paper (which is, admittedly, very long, -but you don't have to read the whole thing): - -http://research.microsoft.com/en-us/um/people/simonpj/papers/higher-rank/ - -Although my explanation will never compete with SPJ's (for one thing, -his is approximately 100 pages), I will attempt to explain the basic -problem and also how we solve it. Note that the paper only discusses -subtyping, not the computation of LUB/GLB. - -The problem we are addressing is that there is a kind of subtyping -between functions with bound region parameters. Consider, for -example, whether the following relation holds: - - for<'a> fn(&'a isize) <: for<'b> fn(&'b isize)? (Yes, a => b) - -The answer is that of course it does. These two types are basically -the same, except that in one we used the name `a` and one we used -the name `b`. - -In the examples that follow, it becomes very important to know whether -a lifetime is bound in a function type (that is, is a lifetime -parameter) or appears free (is defined in some outer scope). -Therefore, from now on I will always write the bindings explicitly, -using the Rust syntax `for<'a> fn(&'a isize)` to indicate that `a` is a -lifetime parameter. - -Now let's consider two more function types. Here, we assume that the -`'b` lifetime is defined somewhere outside and hence is not a lifetime -parameter bound by the function type (it "appears free"): - - for<'a> fn(&'a isize) <: fn(&'b isize)? (Yes, a => b) - -This subtyping relation does in fact hold. To see why, you have to -consider what subtyping means. One way to look at `T1 <: T2` is to -say that it means that it is always ok to treat an instance of `T1` as -if it had the type `T2`. So, with our functions, it is always ok to -treat a function that can take pointers with any lifetime as if it -were a function that can only take a pointer with the specific -lifetime `'b`. After all, `'b` is a lifetime, after all, and -the function can take values of any lifetime. - -You can also look at subtyping as the *is a* relationship. This amounts -to the same thing: a function that accepts pointers with any lifetime -*is a* function that accepts pointers with some specific lifetime. - -So, what if we reverse the order of the two function types, like this: - - fn(&'b isize) <: for<'a> fn(&'a isize)? (No) - -Does the subtyping relationship still hold? The answer of course is -no. In this case, the function accepts *only the lifetime `'b`*, -so it is not reasonable to treat it as if it were a function that -accepted any lifetime. - -What about these two examples: - - for<'a,'b> fn(&'a isize, &'b isize) <: for<'a> fn(&'a isize, &'a isize)? (Yes) - for<'a> fn(&'a isize, &'a isize) <: for<'a,'b> fn(&'a isize, &'b isize)? (No) - -Here, it is true that functions which take two pointers with any two -lifetimes can be treated as if they only accepted two pointers with -the same lifetime, but not the reverse. - -## The algorithm - -Here is the algorithm we use to perform the subtyping check: - -1. Replace all bound regions in the subtype with new variables -2. Replace all bound regions in the supertype with skolemized - equivalents. A "skolemized" region is just a new fresh region - name. -3. Check that the parameter and return types match as normal -4. Ensure that no skolemized regions 'leak' into region variables - visible from "the outside" - -Let's walk through some examples and see how this algorithm plays out. - -#### First example - -We'll start with the first example, which was: - - 1. for<'a> fn(&'a T) <: for<'b> fn(&'b T)? Yes: a -> b - -After steps 1 and 2 of the algorithm we will have replaced the types -like so: - - 1. fn(&'A T) <: fn(&'x T)? - -Here the upper case `&A` indicates a *region variable*, that is, a -region whose value is being inferred by the system. I also replaced -`&b` with `&x`---I'll use letters late in the alphabet (`x`, `y`, `z`) -to indicate skolemized region names. We can assume they don't appear -elsewhere. Note that neither the sub- nor the supertype bind any -region names anymore (as indicated by the absence of `<` and `>`). - -The next step is to check that the parameter types match. Because -parameters are contravariant, this means that we check whether: - - &'x T <: &'A T - -Region pointers are contravariant so this implies that - - &A <= &x - -must hold, where `<=` is the subregion relationship. Processing -*this* constrain simply adds a constraint into our graph that `&A <= -&x` and is considered successful (it can, for example, be satisfied by -choosing the value `&x` for `&A`). - -So far we have encountered no error, so the subtype check succeeds. - -#### The third example - -Now let's look first at the third example, which was: - - 3. fn(&'a T) <: for<'b> fn(&'b T)? No! - -After steps 1 and 2 of the algorithm we will have replaced the types -like so: - - 3. fn(&'a T) <: fn(&'x T)? - -This looks pretty much the same as before, except that on the LHS -`'a` was not bound, and hence was left as-is and not replaced with -a variable. The next step is again to check that the parameter types -match. This will ultimately require (as before) that `'a` <= `&x` -must hold: but this does not hold. `self` and `x` are both distinct -free regions. So the subtype check fails. - -#### Checking for skolemization leaks - -You may be wondering about that mysterious last step in the algorithm. -So far it has not been relevant. The purpose of that last step is to -catch something like *this*: - - for<'a> fn() -> fn(&'a T) <: fn() -> for<'b> fn(&'b T)? No. - -Here the function types are the same but for where the binding occurs. -The subtype returns a function that expects a value in precisely one -region. The supertype returns a function that expects a value in any -region. If we allow an instance of the subtype to be used where the -supertype is expected, then, someone could call the fn and think that -the return value has type `fn(&'b T)` when it really has type -`fn(&'a T)` (this is case #3, above). Bad. - -So let's step through what happens when we perform this subtype check. -We first replace the bound regions in the subtype (the supertype has -no bound regions). This gives us: - - fn() -> fn(&'A T) <: fn() -> for<'b> fn(&'b T)? - -Now we compare the return types, which are covariant, and hence we have: - - fn(&'A T) <: for<'b> fn(&'b T)? - -Here we skolemize the bound region in the supertype to yield: - - fn(&'A T) <: fn(&'x T)? - -And then proceed to compare the argument types: - - &'x T <: &'A T - 'A <= 'x - -Finally, this is where it gets interesting! This is where an error -*should* be reported. But in fact this will not happen. The reason why -is that `A` is a variable: we will infer that its value is the fresh -region `x` and think that everything is happy. In fact, this behavior -is *necessary*, it was key to the first example we walked through. - -The difference between this example and the first one is that the variable -`A` already existed at the point where the skolemization occurred. In -the first example, you had two functions: - - for<'a> fn(&'a T) <: for<'b> fn(&'b T) - -and hence `&A` and `&x` were created "together". In general, the -intention of the skolemized names is that they are supposed to be -fresh names that could never be equal to anything from the outside. -But when inference comes into play, we might not be respecting this -rule. - -So the way we solve this is to add a fourth step that examines the -constraints that refer to skolemized names. Basically, consider a -non-directed version of the constraint graph. Let `Tainted(x)` be the -set of all things reachable from a skolemized variable `x`. -`Tainted(x)` should not contain any regions that existed before the -step at which the skolemization was performed. So this case here -would fail because `&x` was created alone, but is relatable to `&A`. - -## Computing the LUB and GLB - -The paper I pointed you at is written for Haskell. It does not -therefore considering subtyping and in particular does not consider -LUB or GLB computation. We have to consider this. Here is the -algorithm I implemented. - -First though, let's discuss what we are trying to compute in more -detail. The LUB is basically the "common supertype" and the GLB is -"common subtype"; one catch is that the LUB should be the -*most-specific* common supertype and the GLB should be *most general* -common subtype (as opposed to any common supertype or any common -subtype). - -Anyway, to help clarify, here is a table containing some function -pairs and their LUB/GLB (for conciseness, in this table, I'm just -including the lifetimes here, not the rest of the types, and I'm -writing `fn<>` instead of `for<> fn`): - -``` -Type 1 Type 2 LUB GLB -fn<'a>('a) fn('X) fn('X) fn<'a>('a) -fn('a) fn('X) -- fn<'a>('a) -fn<'a,'b>('a, 'b) fn<'x>('x, 'x) fn<'a>('a, 'a) fn<'a,'b>('a, 'b) -fn<'a,'b>('a, 'b, 'a) fn<'x,'y>('x, 'y, 'y) fn<'a>('a, 'a, 'a) fn<'a,'b,'c>('a,'b,'c) -``` - -### Conventions - -I use lower-case letters (e.g., `&a`) for bound regions and upper-case -letters for free regions (`&A`). Region variables written with a -dollar-sign (e.g., `$a`). I will try to remember to enumerate the -bound-regions on the fn type as well (e.g., `for<'a> fn(&a)`). - -### High-level summary - -Both the LUB and the GLB algorithms work in a similar fashion. They -begin by replacing all bound regions (on both sides) with fresh region -inference variables. Therefore, both functions are converted to types -that contain only free regions. We can then compute the LUB/GLB in a -straightforward way, as described in `combine.rs`. This results in an -interim type T. The algorithms then examine the regions that appear -in T and try to, in some cases, replace them with bound regions to -yield the final result. - -To decide whether to replace a region `R` that appears in `T` with -a bound region, the algorithms make use of two bits of -information. First is a set `V` that contains all region -variables created as part of the LUB/GLB computation (roughly; see -`region_vars_confined_to_snapshot()` for full details). `V` will -contain the region variables created to replace the bound regions -in the input types, but it also contains 'intermediate' variables -created to represent the LUB/GLB of individual regions. -Basically, when asked to compute the LUB/GLB of a region variable -with another region, the inferencer cannot oblige immediately -since the values of that variables are not known. Therefore, it -creates a new variable that is related to the two regions. For -example, the LUB of two variables `$x` and `$y` is a fresh -variable `$z` that is constrained such that `$x <= $z` and `$y <= -$z`. So `V` will contain these intermediate variables as well. - -The other important factor in deciding how to replace a region in T is -the function `Tainted($r)` which, for a region variable, identifies -all regions that the region variable is related to in some way -(`Tainted()` made an appearance in the subtype computation as well). - -### LUB - -The LUB algorithm proceeds in three steps: - -1. Replace all bound regions (on both sides) with fresh region - inference variables. -2. Compute the LUB "as normal", meaning compute the GLB of each - pair of argument types and the LUB of the return types and - so forth. Combine those to a new function type `F`. -3. Replace each region `R` that appears in `F` as follows: - - Let `V` be the set of variables created during the LUB - computational steps 1 and 2, as described in the previous section. - - If `R` is not in `V`, replace `R` with itself. - - If `Tainted(R)` contains a region that is not in `V`, - replace `R` with itself. - - Otherwise, select the earliest variable in `Tainted(R)` that originates - from the left-hand side and replace `R` with the bound region that - this variable was a replacement for. - -So, let's work through the simplest example: `fn(&A)` and `for<'a> fn(&a)`. -In this case, `&a` will be replaced with `$a` and the interim LUB type -`fn($b)` will be computed, where `$b=GLB(&A,$a)`. Therefore, `V = -{$a, $b}` and `Tainted($b) = { $b, $a, &A }`. When we go to replace -`$b`, we find that since `&A \in Tainted($b)` is not a member of `V`, -we leave `$b` as is. When region inference happens, `$b` will be -resolved to `&A`, as we wanted. - -Let's look at a more complex one: `fn(&a, &b)` and `fn(&x, &x)`. In -this case, we'll end up with a (pre-replacement) LUB type of `fn(&g, -&h)` and a graph that looks like: - -``` - $a $b *--$x - \ \ / / - \ $h-* / - $g-----------* -``` - -Here `$g` and `$h` are fresh variables that are created to represent -the LUB/GLB of things requiring inference. This means that `V` and -`Tainted` will look like: - -``` -V = {$a, $b, $g, $h, $x} -Tainted($g) = Tainted($h) = { $a, $b, $h, $g, $x } -``` - -Therefore we replace both `$g` and `$h` with `$a`, and end up -with the type `fn(&a, &a)`. - -### GLB - -The procedure for computing the GLB is similar. The difference lies -in computing the replacements for the various variables. For each -region `R` that appears in the type `F`, we again compute `Tainted(R)` -and examine the results: - -1. If `R` is not in `V`, it is not replaced. -2. Else, if `Tainted(R)` contains only variables in `V`, and it - contains exactly one variable from the LHS and one variable from - the RHS, then `R` can be mapped to the bound version of the - variable from the LHS. -3. Else, if `Tainted(R)` contains no variable from the LHS and no - variable from the RHS, then `R` can be mapped to itself. -4. Else, `R` is mapped to a fresh bound variable. - -These rules are pretty complex. Let's look at some examples to see -how they play out. - -Out first example was `fn(&a)` and `fn(&X)`. In this case, `&a` will -be replaced with `$a` and we will ultimately compute a -(pre-replacement) GLB type of `fn($g)` where `$g=LUB($a,&X)`. -Therefore, `V={$a,$g}` and `Tainted($g)={$g,$a,&X}. To find the -replacement for `$g` we consult the rules above: -- Rule (1) does not apply because `$g \in V` -- Rule (2) does not apply because `&X \in Tainted($g)` -- Rule (3) does not apply because `$a \in Tainted($g)` -- Hence, by rule (4), we replace `$g` with a fresh bound variable `&z`. -So our final result is `fn(&z)`, which is correct. - -The next example is `fn(&A)` and `fn(&Z)`. In this case, we will again -have a (pre-replacement) GLB of `fn(&g)`, where `$g = LUB(&A,&Z)`. -Therefore, `V={$g}` and `Tainted($g) = {$g, &A, &Z}`. In this case, -by rule (3), `$g` is mapped to itself, and hence the result is -`fn($g)`. This result is correct (in this case, at least), but it is -indicative of a case that *can* lead us into concluding that there is -no GLB when in fact a GLB does exist. See the section "Questionable -Results" below for more details. - -The next example is `fn(&a, &b)` and `fn(&c, &c)`. In this case, as -before, we'll end up with `F=fn($g, $h)` where `Tainted($g) = -Tainted($h) = {$g, $h, $a, $b, $c}`. Only rule (4) applies and hence -we'll select fresh bound variables `y` and `z` and wind up with -`fn(&y, &z)`. - -For the last example, let's consider what may seem trivial, but is -not: `fn(&a, &a)` and `fn(&b, &b)`. In this case, we'll get `F=fn($g, -$h)` where `Tainted($g) = {$g, $a, $x}` and `Tainted($h) = {$h, $a, -$x}`. Both of these sets contain exactly one bound variable from each -side, so we'll map them both to `&a`, resulting in `fn(&a, &a)`, which -is the desired result. - -### Shortcomings and correctness - -You may be wondering whether this algorithm is correct. The answer is -"sort of". There are definitely cases where they fail to compute a -result even though a correct result exists. I believe, though, that -if they succeed, then the result is valid, and I will attempt to -convince you. The basic argument is that the "pre-replacement" step -computes a set of constraints. The replacements, then, attempt to -satisfy those constraints, using bound identifiers where needed. - -For now I will briefly go over the cases for LUB/GLB and identify -their intent: - -- LUB: - - The region variables that are substituted in place of bound regions - are intended to collect constraints on those bound regions. - - If Tainted(R) contains only values in V, then this region is unconstrained - and can therefore be generalized, otherwise it cannot. -- GLB: - - The region variables that are substituted in place of bound regions - are intended to collect constraints on those bound regions. - - If Tainted(R) contains exactly one variable from each side, and - only variables in V, that indicates that those two bound regions - must be equated. - - Otherwise, if Tainted(R) references any variables from left or right - side, then it is trying to combine a bound region with a free one or - multiple bound regions, so we need to select fresh bound regions. - -Sorry this is more of a shorthand to myself. I will try to write up something -more convincing in the future. - -#### Where are the algorithms wrong? - -- The pre-replacement computation can fail even though using a - bound-region would have succeeded. -- We will compute GLB(fn(fn($a)), fn(fn($b))) as fn($c) where $c is the - GLB of $a and $b. But if inference finds that $a and $b must be mapped - to regions without a GLB, then this is effectively a failure to compute - the GLB. However, the result `fn<$c>(fn($c))` is a valid GLB. diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs deleted file mode 100644 index 44ba6ec4a7a..00000000000 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ /dev/null @@ -1,614 +0,0 @@ -// Copyright 2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Helper routines for higher-ranked things. See the `doc` module at -//! the end of the file for details. - -use super::{CombinedSnapshot, InferCtxt, HigherRankedType, SkolemizationMap}; -use super::combine::CombineFields; - -use middle::ty::{self, TyCtxt, Binder, TypeFoldable}; -use middle::ty::error::TypeError; -use middle::ty::relate::{Relate, RelateResult, TypeRelation}; -use syntax::codemap::Span; -use util::nodemap::{FnvHashMap, FnvHashSet}; - -pub trait HigherRankedRelations<'a,'tcx> { - fn higher_ranked_sub(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> - where T: Relate<'a,'tcx>; - - fn higher_ranked_lub(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> - where T: Relate<'a,'tcx>; - - fn higher_ranked_glb(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> - where T: Relate<'a,'tcx>; -} - -trait InferCtxtExt { - fn tainted_regions(&self, snapshot: &CombinedSnapshot, r: ty::Region) -> Vec; - - fn region_vars_confined_to_snapshot(&self, - snapshot: &CombinedSnapshot) - -> Vec; -} - -impl<'a,'tcx> HigherRankedRelations<'a,'tcx> for CombineFields<'a,'tcx> { - fn higher_ranked_sub(&self, a: &Binder, b: &Binder) - -> RelateResult<'tcx, Binder> - where T: Relate<'a,'tcx> - { - debug!("higher_ranked_sub(a={:?}, b={:?})", - a, b); - - // Rather than checking the subtype relationship between `a` and `b` - // as-is, we need to do some extra work here in order to make sure - // that function subtyping works correctly with respect to regions - // - // Note: this is a subtle algorithm. For a full explanation, - // please see the large comment at the end of the file in the (inlined) module - // `doc`. - - // Start a snapshot so we can examine "all bindings that were - // created as part of this type comparison". - return self.infcx.commit_if_ok(|snapshot| { - // First, we instantiate each bound region in the subtype with a fresh - // region variable. - let (a_prime, _) = - self.infcx.replace_late_bound_regions_with_fresh_var( - self.trace.origin.span(), - HigherRankedType, - a); - - // Second, we instantiate each bound region in the supertype with a - // fresh concrete region. - let (b_prime, skol_map) = - self.infcx.skolemize_late_bound_regions(b, snapshot); - - debug!("a_prime={:?}", a_prime); - debug!("b_prime={:?}", b_prime); - - // Compare types now that bound regions have been replaced. - let result = self.sub().relate(&a_prime, &b_prime)?; - - // Presuming type comparison succeeds, we need to check - // that the skolemized regions do not "leak". - match leak_check(self.infcx, &skol_map, snapshot) { - Ok(()) => { } - Err((skol_br, tainted_region)) => { - if self.a_is_expected { - debug!("Not as polymorphic!"); - return Err(TypeError::RegionsInsufficientlyPolymorphic(skol_br, - tainted_region)); - } else { - debug!("Overly polymorphic!"); - return Err(TypeError::RegionsOverlyPolymorphic(skol_br, - tainted_region)); - } - } - } - - debug!("higher_ranked_sub: OK result={:?}", - result); - - Ok(ty::Binder(result)) - }); - } - - fn higher_ranked_lub(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> - where T: Relate<'a,'tcx> - { - // Start a snapshot so we can examine "all bindings that were - // created as part of this type comparison". - return self.infcx.commit_if_ok(|snapshot| { - // Instantiate each bound region with a fresh region variable. - let span = self.trace.origin.span(); - let (a_with_fresh, a_map) = - self.infcx.replace_late_bound_regions_with_fresh_var( - span, HigherRankedType, a); - let (b_with_fresh, _) = - self.infcx.replace_late_bound_regions_with_fresh_var( - span, HigherRankedType, b); - - // Collect constraints. - let result0 = - self.lub().relate(&a_with_fresh, &b_with_fresh)?; - let result0 = - self.infcx.resolve_type_vars_if_possible(&result0); - debug!("lub result0 = {:?}", result0); - - // Generalize the regions appearing in result0 if possible - let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot); - let span = self.trace.origin.span(); - let result1 = - fold_regions_in( - self.tcx(), - &result0, - |r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn, - &new_vars, &a_map, r)); - - debug!("lub({:?},{:?}) = {:?}", - a, - b, - result1); - - Ok(ty::Binder(result1)) - }); - - fn generalize_region(infcx: &InferCtxt, - span: Span, - snapshot: &CombinedSnapshot, - debruijn: ty::DebruijnIndex, - new_vars: &[ty::RegionVid], - a_map: &FnvHashMap, - r0: ty::Region) - -> ty::Region { - // Regions that pre-dated the LUB computation stay as they are. - if !is_var_in_set(new_vars, r0) { - assert!(!r0.is_bound()); - debug!("generalize_region(r0={:?}): not new variable", r0); - return r0; - } - - let tainted = infcx.tainted_regions(snapshot, r0); - - // Variables created during LUB computation which are - // *related* to regions that pre-date the LUB computation - // stay as they are. - if !tainted.iter().all(|r| is_var_in_set(new_vars, *r)) { - debug!("generalize_region(r0={:?}): \ - non-new-variables found in {:?}", - r0, tainted); - assert!(!r0.is_bound()); - return r0; - } - - // Otherwise, the variable must be associated with at - // least one of the variables representing bound regions - // in both A and B. Replace the variable with the "first" - // bound region from A that we find it to be associated - // with. - for (a_br, a_r) in a_map { - if tainted.iter().any(|x| x == a_r) { - debug!("generalize_region(r0={:?}): \ - replacing with {:?}, tainted={:?}", - r0, *a_br, tainted); - return ty::ReLateBound(debruijn, *a_br); - } - } - - infcx.tcx.sess.span_bug( - span, - &format!("region {:?} is not associated with \ - any bound region from A!", - r0)) - } - } - - fn higher_ranked_glb(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> - where T: Relate<'a,'tcx> - { - debug!("higher_ranked_glb({:?}, {:?})", - a, b); - - // Make a snapshot so we can examine "all bindings that were - // created as part of this type comparison". - return self.infcx.commit_if_ok(|snapshot| { - // Instantiate each bound region with a fresh region variable. - let (a_with_fresh, a_map) = - self.infcx.replace_late_bound_regions_with_fresh_var( - self.trace.origin.span(), HigherRankedType, a); - let (b_with_fresh, b_map) = - self.infcx.replace_late_bound_regions_with_fresh_var( - self.trace.origin.span(), HigherRankedType, b); - let a_vars = var_ids(self, &a_map); - let b_vars = var_ids(self, &b_map); - - // Collect constraints. - let result0 = - self.glb().relate(&a_with_fresh, &b_with_fresh)?; - let result0 = - self.infcx.resolve_type_vars_if_possible(&result0); - debug!("glb result0 = {:?}", result0); - - // Generalize the regions appearing in result0 if possible - let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot); - let span = self.trace.origin.span(); - let result1 = - fold_regions_in( - self.tcx(), - &result0, - |r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn, - &new_vars, - &a_map, &a_vars, &b_vars, - r)); - - debug!("glb({:?},{:?}) = {:?}", - a, - b, - result1); - - Ok(ty::Binder(result1)) - }); - - fn generalize_region(infcx: &InferCtxt, - span: Span, - snapshot: &CombinedSnapshot, - debruijn: ty::DebruijnIndex, - new_vars: &[ty::RegionVid], - a_map: &FnvHashMap, - a_vars: &[ty::RegionVid], - b_vars: &[ty::RegionVid], - r0: ty::Region) -> ty::Region { - if !is_var_in_set(new_vars, r0) { - assert!(!r0.is_bound()); - return r0; - } - - let tainted = infcx.tainted_regions(snapshot, r0); - - let mut a_r = None; - let mut b_r = None; - let mut only_new_vars = true; - for r in &tainted { - if is_var_in_set(a_vars, *r) { - if a_r.is_some() { - return fresh_bound_variable(infcx, debruijn); - } else { - a_r = Some(*r); - } - } else if is_var_in_set(b_vars, *r) { - if b_r.is_some() { - return fresh_bound_variable(infcx, debruijn); - } else { - b_r = Some(*r); - } - } else if !is_var_in_set(new_vars, *r) { - only_new_vars = false; - } - } - - // NB---I do not believe this algorithm computes - // (necessarily) the GLB. As written it can - // spuriously fail. In particular, if there is a case - // like: |fn(&a)| and fn(fn(&b)), where a and b are - // free, it will return fn(&c) where c = GLB(a,b). If - // however this GLB is not defined, then the result is - // an error, even though something like - // "fn(fn(&X))" where X is bound would be a - // subtype of both of those. - // - // The problem is that if we were to return a bound - // variable, we'd be computing a lower-bound, but not - // necessarily the *greatest* lower-bound. - // - // Unfortunately, this problem is non-trivial to solve, - // because we do not know at the time of computing the GLB - // whether a GLB(a,b) exists or not, because we haven't - // run region inference (or indeed, even fully computed - // the region hierarchy!). The current algorithm seems to - // works ok in practice. - - if a_r.is_some() && b_r.is_some() && only_new_vars { - // Related to exactly one bound variable from each fn: - return rev_lookup(infcx, span, a_map, a_r.unwrap()); - } else if a_r.is_none() && b_r.is_none() { - // Not related to bound variables from either fn: - assert!(!r0.is_bound()); - return r0; - } else { - // Other: - return fresh_bound_variable(infcx, debruijn); - } - } - - fn rev_lookup(infcx: &InferCtxt, - span: Span, - a_map: &FnvHashMap, - r: ty::Region) -> ty::Region - { - for (a_br, a_r) in a_map { - if *a_r == r { - return ty::ReLateBound(ty::DebruijnIndex::new(1), *a_br); - } - } - infcx.tcx.sess.span_bug( - span, - &format!("could not find original bound region for {:?}", r)); - } - - fn fresh_bound_variable(infcx: &InferCtxt, debruijn: ty::DebruijnIndex) -> ty::Region { - infcx.region_vars.new_bound(debruijn) - } - } -} - -fn var_ids<'a, 'tcx>(fields: &CombineFields<'a, 'tcx>, - map: &FnvHashMap) - -> Vec { - map.iter() - .map(|(_, r)| match *r { - ty::ReVar(r) => { r } - r => { - fields.tcx().sess.span_bug( - fields.trace.origin.span(), - &format!("found non-region-vid: {:?}", r)); - } - }) - .collect() -} - -fn is_var_in_set(new_vars: &[ty::RegionVid], r: ty::Region) -> bool { - match r { - ty::ReVar(ref v) => new_vars.iter().any(|x| x == v), - _ => false - } -} - -fn fold_regions_in<'tcx, T, F>(tcx: &TyCtxt<'tcx>, - unbound_value: &T, - mut fldr: F) - -> T - where T: TypeFoldable<'tcx>, - F: FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region, -{ - tcx.fold_regions(unbound_value, &mut false, |region, current_depth| { - // we should only be encountering "escaping" late-bound regions here, - // because the ones at the current level should have been replaced - // with fresh variables - assert!(match region { - ty::ReLateBound(..) => false, - _ => true - }); - - fldr(region, ty::DebruijnIndex::new(current_depth)) - }) -} - -impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> { - fn tainted_regions(&self, snapshot: &CombinedSnapshot, r: ty::Region) -> Vec { - self.region_vars.tainted(&snapshot.region_vars_snapshot, r) - } - - fn region_vars_confined_to_snapshot(&self, - snapshot: &CombinedSnapshot) - -> Vec - { - /*! - * Returns the set of region variables that do not affect any - * types/regions which existed before `snapshot` was - * started. This is used in the sub/lub/glb computations. The - * idea here is that when we are computing lub/glb of two - * regions, we sometimes create intermediate region variables. - * Those region variables may touch some of the skolemized or - * other "forbidden" regions we created to replace bound - * regions, but they don't really represent an "external" - * constraint. - * - * However, sometimes fresh variables are created for other - * purposes too, and those *may* represent an external - * constraint. In particular, when a type variable is - * instantiated, we create region variables for all the - * regions that appear within, and if that type variable - * pre-existed the snapshot, then those region variables - * represent external constraints. - * - * An example appears in the unit test - * `sub_free_bound_false_infer`. In this test, we want to - * know whether - * - * ```rust - * fn(_#0t) <: for<'a> fn(&'a int) - * ``` - * - * Note that the subtype has a type variable. Because the type - * variable can't be instantiated with a region that is bound - * in the fn signature, this comparison ought to fail. But if - * we're not careful, it will succeed. - * - * The reason is that when we walk through the subtyping - * algorith, we begin by replacing `'a` with a skolemized - * variable `'1`. We then have `fn(_#0t) <: fn(&'1 int)`. This - * can be made true by unifying `_#0t` with `&'1 int`. In the - * process, we create a fresh variable for the skolemized - * region, `'$2`, and hence we have that `_#0t == &'$2 - * int`. However, because `'$2` was created during the sub - * computation, if we're not careful we will erroneously - * assume it is one of the transient region variables - * representing a lub/glb internally. Not good. - * - * To prevent this, we check for type variables which were - * unified during the snapshot, and say that any region - * variable created during the snapshot but which finds its - * way into a type variable is considered to "escape" the - * snapshot. - */ - - let mut region_vars = - self.region_vars.vars_created_since_snapshot(&snapshot.region_vars_snapshot); - - let escaping_types = - self.type_variables.borrow_mut().types_escaping_snapshot(&snapshot.type_snapshot); - - let mut escaping_region_vars = FnvHashSet(); - for ty in &escaping_types { - self.tcx.collect_regions(ty, &mut escaping_region_vars); - } - - region_vars.retain(|®ion_vid| { - let r = ty::ReVar(region_vid); - !escaping_region_vars.contains(&r) - }); - - debug!("region_vars_confined_to_snapshot: region_vars={:?} escaping_types={:?}", - region_vars, - escaping_types); - - region_vars - } -} - -pub fn skolemize_late_bound_regions<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, - binder: &ty::Binder, - snapshot: &CombinedSnapshot) - -> (T, SkolemizationMap) - where T : TypeFoldable<'tcx> -{ - /*! - * Replace all regions bound by `binder` with skolemized regions and - * return a map indicating which bound-region was replaced with what - * skolemized region. This is the first step of checking subtyping - * when higher-ranked things are involved. See `README.md` for more - * details. - */ - - let (result, map) = infcx.tcx.replace_late_bound_regions(binder, |br| { - infcx.region_vars.new_skolemized(br, &snapshot.region_vars_snapshot) - }); - - debug!("skolemize_bound_regions(binder={:?}, result={:?}, map={:?})", - binder, - result, - map); - - (result, map) -} - -pub fn leak_check<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, - skol_map: &SkolemizationMap, - snapshot: &CombinedSnapshot) - -> Result<(),(ty::BoundRegion,ty::Region)> -{ - /*! - * Searches the region constriants created since `snapshot` was started - * and checks to determine whether any of the skolemized regions created - * in `skol_map` would "escape" -- meaning that they are related to - * other regions in some way. If so, the higher-ranked subtyping doesn't - * hold. See `README.md` for more details. - */ - - debug!("leak_check: skol_map={:?}", - skol_map); - - let new_vars = infcx.region_vars_confined_to_snapshot(snapshot); - for (&skol_br, &skol) in skol_map { - let tainted = infcx.tainted_regions(snapshot, skol); - for &tainted_region in &tainted { - // Each skolemized should only be relatable to itself - // or new variables: - match tainted_region { - ty::ReVar(vid) => { - if new_vars.iter().any(|&x| x == vid) { continue; } - } - _ => { - if tainted_region == skol { continue; } - } - }; - - debug!("{:?} (which replaced {:?}) is tainted by {:?}", - skol, - skol_br, - tainted_region); - - // A is not as polymorphic as B: - return Err((skol_br, tainted_region)); - } - } - Ok(()) -} - -/// This code converts from skolemized regions back to late-bound -/// regions. It works by replacing each region in the taint set of a -/// skolemized region with a bound-region. The bound region will be bound -/// by the outer-most binder in `value`; the caller must ensure that there is -/// such a binder and it is the right place. -/// -/// This routine is only intended to be used when the leak-check has -/// passed; currently, it's used in the trait matching code to create -/// a set of nested obligations frmo an impl that matches against -/// something higher-ranked. More details can be found in -/// `librustc/middle/traits/README.md`. -/// -/// As a brief example, consider the obligation `for<'a> Fn(&'a int) -/// -> &'a int`, and the impl: -/// -/// impl Fn for SomethingOrOther -/// where A : Clone -/// { ... } -/// -/// Here we will have replaced `'a` with a skolemized region -/// `'0`. This means that our substitution will be `{A=>&'0 -/// int, R=>&'0 int}`. -/// -/// When we apply the substitution to the bounds, we will wind up with -/// `&'0 int : Clone` as a predicate. As a last step, we then go and -/// replace `'0` with a late-bound region `'a`. The depth is matched -/// to the depth of the predicate, in this case 1, so that the final -/// predicate is `for<'a> &'a int : Clone`. -pub fn plug_leaks<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, - skol_map: SkolemizationMap, - snapshot: &CombinedSnapshot, - value: &T) - -> T - where T : TypeFoldable<'tcx> -{ - debug_assert!(leak_check(infcx, &skol_map, snapshot).is_ok()); - - debug!("plug_leaks(skol_map={:?}, value={:?})", - skol_map, - value); - - // Compute a mapping from the "taint set" of each skolemized - // region back to the `ty::BoundRegion` that it originally - // represented. Because `leak_check` passed, we know that - // these taint sets are mutually disjoint. - let inv_skol_map: FnvHashMap = - skol_map - .into_iter() - .flat_map(|(skol_br, skol)| { - infcx.tainted_regions(snapshot, skol) - .into_iter() - .map(move |tainted_region| (tainted_region, skol_br)) - }) - .collect(); - - debug!("plug_leaks: inv_skol_map={:?}", - inv_skol_map); - - // Remove any instantiated type variables from `value`; those can hide - // references to regions from the `fold_regions` code below. - let value = infcx.resolve_type_vars_if_possible(value); - - // Map any skolemization byproducts back to a late-bound - // region. Put that late-bound region at whatever the outermost - // binder is that we encountered in `value`. The caller is - // responsible for ensuring that (a) `value` contains at least one - // binder and (b) that binder is the one we want to use. - let result = infcx.tcx.fold_regions(&value, &mut false, |r, current_depth| { - match inv_skol_map.get(&r) { - None => r, - Some(br) => { - // It is the responsibility of the caller to ensure - // that each skolemized region appears within a - // binder. In practice, this routine is only used by - // trait checking, and all of the skolemized regions - // appear inside predicates, which always have - // binders, so this assert is satisfied. - assert!(current_depth > 1); - - ty::ReLateBound(ty::DebruijnIndex::new(current_depth - 1), br.clone()) - } - } - }); - - debug!("plug_leaks: result={:?}", - result); - - result -} diff --git a/src/librustc/middle/infer/lattice.rs b/src/librustc/middle/infer/lattice.rs deleted file mode 100644 index dc4cbd14a5d..00000000000 --- a/src/librustc/middle/infer/lattice.rs +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! # Lattice Variables -//! -//! This file contains generic code for operating on inference variables -//! that are characterized by an upper- and lower-bound. The logic and -//! reasoning is explained in detail in the large comment in `infer.rs`. -//! -//! The code in here is defined quite generically so that it can be -//! applied both to type variables, which represent types being inferred, -//! and fn variables, which represent function types being inferred. -//! It may eventually be applied to their types as well, who knows. -//! In some cases, the functions are also generic with respect to the -//! operation on the lattice (GLB vs LUB). -//! -//! Although all the functions are generic, we generally write the -//! comments in a way that is specific to type variables and the LUB -//! operation. It's just easier that way. -//! -//! In general all of the functions are defined parametrically -//! over a `LatticeValue`, which is a value defined with respect to -//! a lattice. - -use super::combine; -use super::InferCtxt; - -use middle::ty::TyVar; -use middle::ty::{self, Ty}; -use middle::ty::relate::{RelateResult, TypeRelation}; - -pub trait LatticeDir<'f,'tcx> : TypeRelation<'f,'tcx> { - fn infcx(&self) -> &'f InferCtxt<'f, 'tcx>; - - // Relates the type `v` to `a` and `b` such that `v` represents - // the LUB/GLB of `a` and `b` as appropriate. - fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>; -} - -pub fn super_lattice_tys<'a,'tcx,L:LatticeDir<'a,'tcx>>(this: &mut L, - a: Ty<'tcx>, - b: Ty<'tcx>) - -> RelateResult<'tcx, Ty<'tcx>> - where 'tcx: 'a -{ - debug!("{}.lattice_tys({:?}, {:?})", - this.tag(), - a, - b); - - if a == b { - return Ok(a); - } - - let infcx = this.infcx(); - let a = infcx.type_variables.borrow_mut().replace_if_possible(a); - let b = infcx.type_variables.borrow_mut().replace_if_possible(b); - match (&a.sty, &b.sty) { - (&ty::TyInfer(TyVar(..)), &ty::TyInfer(TyVar(..))) - if infcx.type_var_diverges(a) && infcx.type_var_diverges(b) => { - let v = infcx.next_diverging_ty_var(); - this.relate_bound(v, a, b)?; - Ok(v) - } - - (&ty::TyInfer(TyVar(..)), _) | - (_, &ty::TyInfer(TyVar(..))) => { - let v = infcx.next_ty_var(); - this.relate_bound(v, a, b)?; - Ok(v) - } - - _ => { - combine::super_combine_tys(this.infcx(), this, a, b) - } - } -} diff --git a/src/librustc/middle/infer/lub.rs b/src/librustc/middle/infer/lub.rs deleted file mode 100644 index 7202e4afc5a..00000000000 --- a/src/librustc/middle/infer/lub.rs +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::combine::CombineFields; -use super::higher_ranked::HigherRankedRelations; -use super::InferCtxt; -use super::lattice::{self, LatticeDir}; -use super::Subtype; - -use middle::ty::{self, Ty, TyCtxt}; -use middle::ty::relate::{Relate, RelateResult, TypeRelation}; - -/// "Least upper bound" (common supertype) -pub struct Lub<'a, 'tcx: 'a> { - fields: CombineFields<'a, 'tcx> -} - -impl<'a, 'tcx> Lub<'a, 'tcx> { - pub fn new(fields: CombineFields<'a, 'tcx>) -> Lub<'a, 'tcx> { - Lub { fields: fields } - } -} - -impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Lub<'a, 'tcx> { - fn tag(&self) -> &'static str { "Lub" } - - fn tcx(&self) -> &'a TyCtxt<'tcx> { self.fields.tcx() } - - fn a_is_expected(&self) -> bool { self.fields.a_is_expected } - - fn relate_with_variance>(&mut self, - variance: ty::Variance, - a: &T, - b: &T) - -> RelateResult<'tcx, T> - { - match variance { - ty::Invariant => self.fields.equate().relate(a, b), - ty::Covariant => self.relate(a, b), - ty::Bivariant => self.fields.bivariate().relate(a, b), - ty::Contravariant => self.fields.glb().relate(a, b), - } - } - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - lattice::super_lattice_tys(self, a, b) - } - - fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> { - debug!("{}.regions({:?}, {:?})", - self.tag(), - a, - b); - - let origin = Subtype(self.fields.trace.clone()); - Ok(self.fields.infcx.region_vars.lub_regions(origin, a, b)) - } - - fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) - -> RelateResult<'tcx, ty::Binder> - where T: Relate<'a, 'tcx> - { - self.fields.higher_ranked_lub(a, b) - } -} - -impl<'a, 'tcx> LatticeDir<'a,'tcx> for Lub<'a, 'tcx> { - fn infcx(&self) -> &'a InferCtxt<'a,'tcx> { - self.fields.infcx - } - - fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { - let mut sub = self.fields.sub(); - sub.relate(&a, &v)?; - sub.relate(&b, &v)?; - Ok(()) - } -} diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs deleted file mode 100644 index ea11ade1d16..00000000000 --- a/src/librustc/middle/infer/mod.rs +++ /dev/null @@ -1,1672 +0,0 @@ -// Copyright 2012-2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! See the Book for more information. - -pub use self::LateBoundRegionConversionTime::*; -pub use self::RegionVariableOrigin::*; -pub use self::SubregionOrigin::*; -pub use self::ValuePairs::*; -pub use middle::ty::IntVarValue; -pub use self::freshen::TypeFreshener; -pub use self::region_inference::{GenericKind, VerifyBound}; - -use middle::def_id::DefId; -use rustc_front::hir; -use middle::free_region::FreeRegionMap; -use middle::mem_categorization as mc; -use middle::mem_categorization::McResult; -use middle::region::CodeExtent; -use middle::ty::subst; -use middle::ty::subst::Substs; -use middle::ty::subst::Subst; -use middle::traits::{self, ProjectionMode}; -use middle::ty::adjustment; -use middle::ty::{TyVid, IntVid, FloatVid}; -use middle::ty::{self, Ty, TyCtxt}; -use middle::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; -use middle::ty::fold::{TypeFolder, TypeFoldable}; -use middle::ty::relate::{Relate, RelateResult, TypeRelation}; -use rustc_data_structures::unify::{self, UnificationTable}; -use std::cell::{RefCell, Ref}; -use std::fmt; -use syntax::ast; -use syntax::codemap; -use syntax::codemap::{Span, DUMMY_SP}; -use syntax::errors::DiagnosticBuilder; -use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap}; - -use self::combine::CombineFields; -use self::region_inference::{RegionVarBindings, RegionSnapshot}; -use self::error_reporting::ErrorReporting; -use self::unify_key::ToType; - -pub mod bivariate; -pub mod combine; -pub mod equate; -pub mod error_reporting; -pub mod glb; -mod higher_ranked; -pub mod lattice; -pub mod lub; -pub mod region_inference; -pub mod resolve; -mod freshen; -pub mod sub; -pub mod type_variable; -pub mod unify_key; - -pub type Bound = Option; -pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result" -pub type FixupResult = Result; // "fixup result" - -pub struct InferCtxt<'a, 'tcx: 'a> { - pub tcx: &'a TyCtxt<'tcx>, - - pub tables: &'a RefCell>, - - // We instantiate UnificationTable with bounds because the - // types that might instantiate a general type variable have an - // order, represented by its upper and lower bounds. - type_variables: RefCell>, - - // Map from integral variable to the kind of integer it represents - int_unification_table: RefCell>, - - // Map from floating variable to the kind of float it represents - float_unification_table: RefCell>, - - // For region variables. - region_vars: RegionVarBindings<'a, 'tcx>, - - pub parameter_environment: ty::ParameterEnvironment<'a, 'tcx>, - - // the set of predicates on which errors have been reported, to - // avoid reporting the same error twice. - pub reported_trait_errors: RefCell>>, - - // This is a temporary field used for toggling on normalization in the inference context, - // as we move towards the approach described here: - // https://internals.rust-lang.org/t/flattening-the-contexts-for-fun-and-profit/2293 - // At a point sometime in the future normalization will be done by the typing context - // directly. - normalize: bool, - - // Sadly, the behavior of projection varies a bit depending on the - // stage of compilation. The specifics are given in the - // documentation for `ProjectionMode`. - projection_mode: ProjectionMode, - - err_count_on_creation: usize, -} - -/// A map returned by `skolemize_late_bound_regions()` indicating the skolemized -/// region that each late-bound region was replaced with. -pub type SkolemizationMap = FnvHashMap; - -/// Why did we require that the two types be related? -/// -/// See `error_reporting.rs` for more details -#[derive(Clone, Copy, Debug)] -pub enum TypeOrigin { - // Not yet categorized in a better way - Misc(Span), - - // Checking that method of impl is compatible with trait - MethodCompatCheck(Span), - - // Checking that this expression can be assigned where it needs to be - // FIXME(eddyb) #11161 is the original Expr required? - ExprAssignable(Span), - - // Relating trait refs when resolving vtables - RelateTraitRefs(Span), - - // Relating self types when resolving vtables - RelateSelfType(Span), - - // Relating trait type parameters to those found in impl etc - RelateOutputImplTypes(Span), - - // Computing common supertype in the arms of a match expression - MatchExpressionArm(Span, Span, hir::MatchSource), - - // Computing common supertype in an if expression - IfExpression(Span), - - // Computing common supertype of an if expression with no else counter-part - IfExpressionWithNoElse(Span), - - // Computing common supertype in a range expression - RangeExpression(Span), - - // `where a == b` - EquatePredicate(Span), -} - -impl TypeOrigin { - fn as_str(&self) -> &'static str { - match self { - &TypeOrigin::Misc(_) | - &TypeOrigin::RelateSelfType(_) | - &TypeOrigin::RelateOutputImplTypes(_) | - &TypeOrigin::ExprAssignable(_) => "mismatched types", - &TypeOrigin::RelateTraitRefs(_) => "mismatched traits", - &TypeOrigin::MethodCompatCheck(_) => "method not compatible with trait", - &TypeOrigin::MatchExpressionArm(_, _, source) => match source { - hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types", - _ => "match arms have incompatible types", - }, - &TypeOrigin::IfExpression(_) => "if and else have incompatible types", - &TypeOrigin::IfExpressionWithNoElse(_) => "if may be missing an else clause", - &TypeOrigin::RangeExpression(_) => "start and end of range have incompatible types", - &TypeOrigin::EquatePredicate(_) => "equality predicate not satisfied", - } - } -} - -impl fmt::Display for TypeOrigin { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(),fmt::Error> { - fmt::Display::fmt(self.as_str(), f) - } -} - -/// See `error_reporting.rs` for more details -#[derive(Clone, Debug)] -pub enum ValuePairs<'tcx> { - Types(ExpectedFound>), - TraitRefs(ExpectedFound>), - PolyTraitRefs(ExpectedFound>), -} - -/// The trace designates the path through inference that we took to -/// encounter an error or subtyping constraint. -/// -/// See `error_reporting.rs` for more details. -#[derive(Clone)] -pub struct TypeTrace<'tcx> { - origin: TypeOrigin, - values: ValuePairs<'tcx>, -} - -/// The origin of a `r1 <= r2` constraint. -/// -/// See `error_reporting.rs` for more details -#[derive(Clone, Debug)] -pub enum SubregionOrigin<'tcx> { - // Arose from a subtyping relation - Subtype(TypeTrace<'tcx>), - - // Stack-allocated closures cannot outlive innermost loop - // or function so as to ensure we only require finite stack - InfStackClosure(Span), - - // Invocation of closure must be within its lifetime - InvokeClosure(Span), - - // Dereference of reference must be within its lifetime - DerefPointer(Span), - - // Closure bound must not outlive captured free variables - FreeVariable(Span, ast::NodeId), - - // Index into slice must be within its lifetime - IndexSlice(Span), - - // When casting `&'a T` to an `&'b Trait` object, - // relating `'a` to `'b` - RelateObjectBound(Span), - - // Some type parameter was instantiated with the given type, - // and that type must outlive some region. - RelateParamBound(Span, Ty<'tcx>), - - // The given region parameter was instantiated with a region - // that must outlive some other region. - RelateRegionParamBound(Span), - - // A bound placed on type parameters that states that must outlive - // the moment of their instantiation. - RelateDefaultParamBound(Span, Ty<'tcx>), - - // Creating a pointer `b` to contents of another reference - Reborrow(Span), - - // Creating a pointer `b` to contents of an upvar - ReborrowUpvar(Span, ty::UpvarId), - - // Data with type `Ty<'tcx>` was borrowed - DataBorrowed(Ty<'tcx>, Span), - - // (&'a &'b T) where a >= b - ReferenceOutlivesReferent(Ty<'tcx>, Span), - - // Type or region parameters must be in scope. - ParameterInScope(ParameterOrigin, Span), - - // The type T of an expression E must outlive the lifetime for E. - ExprTypeIsNotInScope(Ty<'tcx>, Span), - - // A `ref b` whose region does not enclose the decl site - BindingTypeIsNotValidAtDecl(Span), - - // Regions appearing in a method receiver must outlive method call - CallRcvr(Span), - - // Regions appearing in a function argument must outlive func call - CallArg(Span), - - // Region in return type of invoked fn must enclose call - CallReturn(Span), - - // Operands must be in scope - Operand(Span), - - // Region resulting from a `&` expr must enclose the `&` expr - AddrOf(Span), - - // An auto-borrow that does not enclose the expr where it occurs - AutoBorrow(Span), - - // Region constraint arriving from destructor safety - SafeDestructor(Span), -} - -/// Places that type/region parameters can appear. -#[derive(Clone, Copy, Debug)] -pub enum ParameterOrigin { - Path, // foo::bar - MethodCall, // foo.bar() <-- parameters on impl providing bar() - OverloadedOperator, // a + b when overloaded - OverloadedDeref, // *a when overloaded -} - -/// Times when we replace late-bound regions with variables: -#[derive(Clone, Copy, Debug)] -pub enum LateBoundRegionConversionTime { - /// when a fn is called - FnCall, - - /// when two higher-ranked types are compared - HigherRankedType, - - /// when projecting an associated type - AssocTypeProjection(ast::Name), -} - -/// Reasons to create a region inference variable -/// -/// See `error_reporting.rs` for more details -#[derive(Clone, Debug)] -pub enum RegionVariableOrigin { - // Region variables created for ill-categorized reasons, - // mostly indicates places in need of refactoring - MiscVariable(Span), - - // Regions created by a `&P` or `[...]` pattern - PatternRegion(Span), - - // Regions created by `&` operator - AddrOfRegion(Span), - - // Regions created as part of an autoref of a method receiver - Autoref(Span), - - // Regions created as part of an automatic coercion - Coercion(Span), - - // Region variables created as the values for early-bound regions - EarlyBoundRegion(Span, ast::Name), - - // Region variables created for bound regions - // in a function or method that is called - LateBoundRegion(Span, ty::BoundRegion, LateBoundRegionConversionTime), - - UpvarRegion(ty::UpvarId, Span), - - BoundRegionInCoherence(ast::Name), -} - -#[derive(Copy, Clone, Debug)] -pub enum FixupError { - UnresolvedIntTy(IntVid), - UnresolvedFloatTy(FloatVid), - UnresolvedTy(TyVid) -} - -pub fn fixup_err_to_string(f: FixupError) -> String { - use self::FixupError::*; - - match f { - UnresolvedIntTy(_) => { - "cannot determine the type of this integer; add a suffix to \ - specify the type explicitly".to_string() - } - UnresolvedFloatTy(_) => { - "cannot determine the type of this number; add a suffix to specify \ - the type explicitly".to_string() - } - UnresolvedTy(_) => "unconstrained type".to_string(), - } -} - -pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a TyCtxt<'tcx>, - tables: &'a RefCell>, - param_env: Option>, - projection_mode: ProjectionMode) - -> InferCtxt<'a, 'tcx> { - InferCtxt { - tcx: tcx, - tables: tables, - type_variables: RefCell::new(type_variable::TypeVariableTable::new()), - int_unification_table: RefCell::new(UnificationTable::new()), - float_unification_table: RefCell::new(UnificationTable::new()), - region_vars: RegionVarBindings::new(tcx), - parameter_environment: param_env.unwrap_or(tcx.empty_parameter_environment()), - reported_trait_errors: RefCell::new(FnvHashSet()), - normalize: false, - projection_mode: projection_mode, - err_count_on_creation: tcx.sess.err_count() - } -} - -pub fn normalizing_infer_ctxt<'a, 'tcx>(tcx: &'a TyCtxt<'tcx>, - tables: &'a RefCell>, - projection_mode: ProjectionMode) - -> InferCtxt<'a, 'tcx> { - let mut infcx = new_infer_ctxt(tcx, tables, None, projection_mode); - infcx.normalize = true; - infcx -} - -/// Computes the least upper-bound of `a` and `b`. If this is not possible, reports an error and -/// returns ty::err. -pub fn common_supertype<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, - origin: TypeOrigin, - a_is_expected: bool, - a: Ty<'tcx>, - b: Ty<'tcx>) - -> Ty<'tcx> -{ - debug!("common_supertype({:?}, {:?})", - a, b); - - let trace = TypeTrace { - origin: origin, - values: Types(expected_found(a_is_expected, a, b)) - }; - - let result = cx.commit_if_ok(|_| cx.lub(a_is_expected, trace.clone()).relate(&a, &b)); - match result { - Ok(t) => t, - Err(ref err) => { - cx.report_and_explain_type_error(trace, err).emit(); - cx.tcx.types.err - } - } -} - -pub fn mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, - a_is_expected: bool, - origin: TypeOrigin, - a: Ty<'tcx>, - b: Ty<'tcx>) - -> UnitResult<'tcx> -{ - debug!("mk_subty({:?} <: {:?})", a, b); - cx.sub_types(a_is_expected, origin, a, b) -} - -pub fn can_mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, - a: Ty<'tcx>, - b: Ty<'tcx>) - -> UnitResult<'tcx> { - debug!("can_mk_subty({:?} <: {:?})", a, b); - cx.probe(|_| { - let trace = TypeTrace { - origin: TypeOrigin::Misc(codemap::DUMMY_SP), - values: Types(expected_found(true, a, b)) - }; - cx.sub(true, trace).relate(&a, &b).map(|_| ()) - }) -} - -pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) - -> UnitResult<'tcx> -{ - cx.can_equate(&a, &b) -} - -pub fn mk_subr<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, - origin: SubregionOrigin<'tcx>, - a: ty::Region, - b: ty::Region) { - debug!("mk_subr({:?} <: {:?})", a, b); - let snapshot = cx.region_vars.start_snapshot(); - cx.region_vars.make_subregion(origin, a, b); - cx.region_vars.commit(snapshot); -} - -pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, - a_is_expected: bool, - origin: TypeOrigin, - a: Ty<'tcx>, - b: Ty<'tcx>) - -> UnitResult<'tcx> -{ - debug!("mk_eqty({:?} <: {:?})", a, b); - cx.eq_types(a_is_expected, origin, a, b) -} - -pub fn mk_eq_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, - a_is_expected: bool, - origin: TypeOrigin, - a: ty::TraitRef<'tcx>, - b: ty::TraitRef<'tcx>) - -> UnitResult<'tcx> -{ - debug!("mk_eq_trait_refs({:?} = {:?})", a, b); - cx.eq_trait_refs(a_is_expected, origin, a, b) -} - -pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, - a_is_expected: bool, - origin: TypeOrigin, - a: ty::PolyTraitRef<'tcx>, - b: ty::PolyTraitRef<'tcx>) - -> UnitResult<'tcx> -{ - debug!("mk_sub_poly_trait_refs({:?} <: {:?})", a, b); - cx.sub_poly_trait_refs(a_is_expected, origin, a, b) -} - -pub fn mk_eq_impl_headers<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, - a_is_expected: bool, - origin: TypeOrigin, - a: &ty::ImplHeader<'tcx>, - b: &ty::ImplHeader<'tcx>) - -> UnitResult<'tcx> -{ - debug!("mk_eq_impl_header({:?} = {:?})", a, b); - match (a.trait_ref, b.trait_ref) { - (Some(a_ref), Some(b_ref)) => mk_eq_trait_refs(cx, a_is_expected, origin, a_ref, b_ref), - (None, None) => mk_eqty(cx, a_is_expected, origin, a.self_ty, b.self_ty), - _ => cx.tcx.sess.bug("mk_eq_impl_headers given mismatched impl kinds"), - } -} - -fn expected_found(a_is_expected: bool, - a: T, - b: T) - -> ExpectedFound -{ - if a_is_expected { - ExpectedFound {expected: a, found: b} - } else { - ExpectedFound {expected: b, found: a} - } -} - -#[must_use = "once you start a snapshot, you should always consume it"] -pub struct CombinedSnapshot { - type_snapshot: type_variable::Snapshot, - int_snapshot: unify::Snapshot, - float_snapshot: unify::Snapshot, - region_vars_snapshot: RegionSnapshot, -} - -// NOTE: Callable from trans only! -pub fn normalize_associated_type<'tcx,T>(tcx: &TyCtxt<'tcx>, value: &T) -> T - where T : TypeFoldable<'tcx> -{ - debug!("normalize_associated_type(t={:?})", value); - - let value = tcx.erase_regions(value); - - if !value.has_projection_types() { - return value; - } - - let infcx = new_infer_ctxt(tcx, &tcx.tables, None, ProjectionMode::Any); - let mut selcx = traits::SelectionContext::new(&infcx); - let cause = traits::ObligationCause::dummy(); - let traits::Normalized { value: result, obligations } = - traits::normalize(&mut selcx, cause, &value); - - debug!("normalize_associated_type: result={:?} obligations={:?}", - result, - obligations); - - let mut fulfill_cx = traits::FulfillmentContext::new(); - - for obligation in obligations { - fulfill_cx.register_predicate_obligation(&infcx, obligation); - } - - drain_fulfillment_cx_or_panic(DUMMY_SP, &infcx, &mut fulfill_cx, &result) -} - -pub fn drain_fulfillment_cx_or_panic<'a,'tcx,T>(span: Span, - infcx: &InferCtxt<'a,'tcx>, - fulfill_cx: &mut traits::FulfillmentContext<'tcx>, - result: &T) - -> T - where T : TypeFoldable<'tcx> -{ - match drain_fulfillment_cx(infcx, fulfill_cx, result) { - Ok(v) => v, - Err(errors) => { - infcx.tcx.sess.span_bug( - span, - &format!("Encountered errors `{:?}` fulfilling during trans", - errors)); - } - } -} - -/// Finishes processes any obligations that remain in the fulfillment -/// context, and then "freshens" and returns `result`. This is -/// primarily used during normalization and other cases where -/// processing the obligations in `fulfill_cx` may cause type -/// inference variables that appear in `result` to be unified, and -/// hence we need to process those obligations to get the complete -/// picture of the type. -pub fn drain_fulfillment_cx<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, - fulfill_cx: &mut traits::FulfillmentContext<'tcx>, - result: &T) - -> Result>> - where T : TypeFoldable<'tcx> -{ - debug!("drain_fulfillment_cx(result={:?})", - result); - - // In principle, we only need to do this so long as `result` - // contains unbound type parameters. It could be a slight - // optimization to stop iterating early. - match fulfill_cx.select_all_or_error(infcx) { - Ok(()) => { } - Err(errors) => { - return Err(errors); - } - } - - let result = infcx.resolve_type_vars_if_possible(result); - Ok(infcx.tcx.erase_regions(&result)) -} - -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - pub fn projection_mode(&self) -> ProjectionMode { - self.projection_mode - } - - pub fn freshen>(&self, t: T) -> T { - t.fold_with(&mut self.freshener()) - } - - pub fn type_var_diverges(&'a self, ty: Ty) -> bool { - match ty.sty { - ty::TyInfer(ty::TyVar(vid)) => self.type_variables.borrow().var_diverges(vid), - _ => false - } - } - - pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx> { - freshen::TypeFreshener::new(self) - } - - pub fn type_is_unconstrained_numeric(&'a self, ty: Ty) -> UnconstrainedNumeric { - use middle::ty::error::UnconstrainedNumeric::Neither; - use middle::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; - match ty.sty { - ty::TyInfer(ty::IntVar(vid)) => { - if self.int_unification_table.borrow_mut().has_value(vid) { - Neither - } else { - UnconstrainedInt - } - }, - ty::TyInfer(ty::FloatVar(vid)) => { - if self.float_unification_table.borrow_mut().has_value(vid) { - Neither - } else { - UnconstrainedFloat - } - }, - _ => Neither, - } - } - - /// Returns a type variable's default fallback if any exists. A default - /// must be attached to the variable when created, if it is created - /// without a default, this will return None. - /// - /// This code does not apply to integral or floating point variables, - /// only to use declared defaults. - /// - /// See `new_ty_var_with_default` to create a type variable with a default. - /// See `type_variable::Default` for details about what a default entails. - pub fn default(&self, ty: Ty<'tcx>) -> Option> { - match ty.sty { - ty::TyInfer(ty::TyVar(vid)) => self.type_variables.borrow().default(vid), - _ => None - } - } - - pub fn unsolved_variables(&self) -> Vec> { - let mut variables = Vec::new(); - - let unbound_ty_vars = self.type_variables - .borrow_mut() - .unsolved_variables() - .into_iter() - .map(|t| self.tcx.mk_var(t)); - - let unbound_int_vars = self.int_unification_table - .borrow_mut() - .unsolved_variables() - .into_iter() - .map(|v| self.tcx.mk_int_var(v)); - - let unbound_float_vars = self.float_unification_table - .borrow_mut() - .unsolved_variables() - .into_iter() - .map(|v| self.tcx.mk_float_var(v)); - - variables.extend(unbound_ty_vars); - variables.extend(unbound_int_vars); - variables.extend(unbound_float_vars); - - return variables; - } - - fn combine_fields(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>) - -> CombineFields<'a, 'tcx> { - CombineFields {infcx: self, - a_is_expected: a_is_expected, - trace: trace, - cause: None} - } - - // public so that it can be used from the rustc_driver unit tests - pub fn equate(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>) - -> equate::Equate<'a, 'tcx> - { - self.combine_fields(a_is_expected, trace).equate() - } - - // public so that it can be used from the rustc_driver unit tests - pub fn sub(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>) - -> sub::Sub<'a, 'tcx> - { - self.combine_fields(a_is_expected, trace).sub() - } - - // public so that it can be used from the rustc_driver unit tests - pub fn lub(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>) - -> lub::Lub<'a, 'tcx> - { - self.combine_fields(a_is_expected, trace).lub() - } - - // public so that it can be used from the rustc_driver unit tests - pub fn glb(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>) - -> glb::Glb<'a, 'tcx> - { - self.combine_fields(a_is_expected, trace).glb() - } - - fn start_snapshot(&self) -> CombinedSnapshot { - CombinedSnapshot { - type_snapshot: self.type_variables.borrow_mut().snapshot(), - int_snapshot: self.int_unification_table.borrow_mut().snapshot(), - float_snapshot: self.float_unification_table.borrow_mut().snapshot(), - region_vars_snapshot: self.region_vars.start_snapshot(), - } - } - - fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot) { - debug!("rollback_to(cause={})", cause); - let CombinedSnapshot { type_snapshot, - int_snapshot, - float_snapshot, - region_vars_snapshot } = snapshot; - - self.type_variables - .borrow_mut() - .rollback_to(type_snapshot); - self.int_unification_table - .borrow_mut() - .rollback_to(int_snapshot); - self.float_unification_table - .borrow_mut() - .rollback_to(float_snapshot); - self.region_vars - .rollback_to(region_vars_snapshot); - } - - fn commit_from(&self, snapshot: CombinedSnapshot) { - debug!("commit_from!"); - let CombinedSnapshot { type_snapshot, - int_snapshot, - float_snapshot, - region_vars_snapshot } = snapshot; - - self.type_variables - .borrow_mut() - .commit(type_snapshot); - self.int_unification_table - .borrow_mut() - .commit(int_snapshot); - self.float_unification_table - .borrow_mut() - .commit(float_snapshot); - self.region_vars - .commit(region_vars_snapshot); - } - - /// Execute `f` and commit the bindings - pub fn commit_unconditionally(&self, f: F) -> R where - F: FnOnce() -> R, - { - debug!("commit()"); - let snapshot = self.start_snapshot(); - let r = f(); - self.commit_from(snapshot); - r - } - - /// Execute `f` and commit the bindings if closure `f` returns `Ok(_)` - pub fn commit_if_ok(&self, f: F) -> Result where - F: FnOnce(&CombinedSnapshot) -> Result - { - debug!("commit_if_ok()"); - let snapshot = self.start_snapshot(); - let r = f(&snapshot); - debug!("commit_if_ok() -- r.is_ok() = {}", r.is_ok()); - match r { - Ok(_) => { self.commit_from(snapshot); } - Err(_) => { self.rollback_to("commit_if_ok -- error", snapshot); } - } - r - } - - /// Execute `f` and commit only the region bindings if successful. - /// The function f must be very careful not to leak any non-region - /// variables that get created. - pub fn commit_regions_if_ok(&self, f: F) -> Result where - F: FnOnce() -> Result - { - debug!("commit_regions_if_ok()"); - let CombinedSnapshot { type_snapshot, - int_snapshot, - float_snapshot, - region_vars_snapshot } = self.start_snapshot(); - - let r = self.commit_if_ok(|_| f()); - - debug!("commit_regions_if_ok: rolling back everything but regions"); - - // Roll back any non-region bindings - they should be resolved - // inside `f`, with, e.g. `resolve_type_vars_if_possible`. - self.type_variables - .borrow_mut() - .rollback_to(type_snapshot); - self.int_unification_table - .borrow_mut() - .rollback_to(int_snapshot); - self.float_unification_table - .borrow_mut() - .rollback_to(float_snapshot); - - // Commit region vars that may escape through resolved types. - self.region_vars - .commit(region_vars_snapshot); - - r - } - - /// Execute `f` then unroll any bindings it creates - pub fn probe(&self, f: F) -> R where - F: FnOnce(&CombinedSnapshot) -> R, - { - debug!("probe()"); - let snapshot = self.start_snapshot(); - let r = f(&snapshot); - self.rollback_to("probe", snapshot); - r - } - - pub fn add_given(&self, - sub: ty::FreeRegion, - sup: ty::RegionVid) - { - self.region_vars.add_given(sub, sup); - } - - pub fn sub_types(&self, - a_is_expected: bool, - origin: TypeOrigin, - a: Ty<'tcx>, - b: Ty<'tcx>) - -> UnitResult<'tcx> - { - debug!("sub_types({:?} <: {:?})", a, b); - self.commit_if_ok(|_| { - let trace = TypeTrace::types(origin, a_is_expected, a, b); - self.sub(a_is_expected, trace).relate(&a, &b).map(|_| ()) - }) - } - - pub fn eq_types(&self, - a_is_expected: bool, - origin: TypeOrigin, - a: Ty<'tcx>, - b: Ty<'tcx>) - -> UnitResult<'tcx> - { - self.commit_if_ok(|_| { - let trace = TypeTrace::types(origin, a_is_expected, a, b); - self.equate(a_is_expected, trace).relate(&a, &b).map(|_| ()) - }) - } - - pub fn eq_trait_refs(&self, - a_is_expected: bool, - origin: TypeOrigin, - a: ty::TraitRef<'tcx>, - b: ty::TraitRef<'tcx>) - -> UnitResult<'tcx> - { - debug!("eq_trait_refs({:?} <: {:?})", - a, - b); - self.commit_if_ok(|_| { - let trace = TypeTrace { - origin: origin, - values: TraitRefs(expected_found(a_is_expected, a.clone(), b.clone())) - }; - self.equate(a_is_expected, trace).relate(&a, &b).map(|_| ()) - }) - } - - pub fn sub_poly_trait_refs(&self, - a_is_expected: bool, - origin: TypeOrigin, - a: ty::PolyTraitRef<'tcx>, - b: ty::PolyTraitRef<'tcx>) - -> UnitResult<'tcx> - { - debug!("sub_poly_trait_refs({:?} <: {:?})", - a, - b); - self.commit_if_ok(|_| { - let trace = TypeTrace { - origin: origin, - values: PolyTraitRefs(expected_found(a_is_expected, a.clone(), b.clone())) - }; - self.sub(a_is_expected, trace).relate(&a, &b).map(|_| ()) - }) - } - - pub fn skolemize_late_bound_regions(&self, - value: &ty::Binder, - snapshot: &CombinedSnapshot) - -> (T, SkolemizationMap) - where T : TypeFoldable<'tcx> - { - /*! See `higher_ranked::skolemize_late_bound_regions` */ - - higher_ranked::skolemize_late_bound_regions(self, value, snapshot) - } - - pub fn leak_check(&self, - skol_map: &SkolemizationMap, - snapshot: &CombinedSnapshot) - -> UnitResult<'tcx> - { - /*! See `higher_ranked::leak_check` */ - - match higher_ranked::leak_check(self, skol_map, snapshot) { - Ok(()) => Ok(()), - Err((br, r)) => Err(TypeError::RegionsInsufficientlyPolymorphic(br, r)) - } - } - - pub fn plug_leaks(&self, - skol_map: SkolemizationMap, - snapshot: &CombinedSnapshot, - value: &T) - -> T - where T : TypeFoldable<'tcx> - { - /*! See `higher_ranked::plug_leaks` */ - - higher_ranked::plug_leaks(self, skol_map, snapshot, value) - } - - pub fn equality_predicate(&self, - span: Span, - predicate: &ty::PolyEquatePredicate<'tcx>) - -> UnitResult<'tcx> { - self.commit_if_ok(|snapshot| { - let (ty::EquatePredicate(a, b), skol_map) = - self.skolemize_late_bound_regions(predicate, snapshot); - let origin = TypeOrigin::EquatePredicate(span); - let () = mk_eqty(self, false, origin, a, b)?; - self.leak_check(&skol_map, snapshot) - }) - } - - pub fn region_outlives_predicate(&self, - span: Span, - predicate: &ty::PolyRegionOutlivesPredicate) - -> UnitResult<'tcx> { - self.commit_if_ok(|snapshot| { - let (ty::OutlivesPredicate(r_a, r_b), skol_map) = - self.skolemize_late_bound_regions(predicate, snapshot); - let origin = RelateRegionParamBound(span); - let () = mk_subr(self, origin, r_b, r_a); // `b : a` ==> `a <= b` - self.leak_check(&skol_map, snapshot) - }) - } - - pub fn next_ty_var_id(&self, diverging: bool) -> TyVid { - self.type_variables - .borrow_mut() - .new_var(diverging, None) - } - - pub fn next_ty_var(&self) -> Ty<'tcx> { - self.tcx.mk_var(self.next_ty_var_id(false)) - } - - pub fn next_ty_var_with_default(&self, - default: Option>) -> Ty<'tcx> { - let ty_var_id = self.type_variables - .borrow_mut() - .new_var(false, default); - - self.tcx.mk_var(ty_var_id) - } - - pub fn next_diverging_ty_var(&self) -> Ty<'tcx> { - self.tcx.mk_var(self.next_ty_var_id(true)) - } - - pub fn next_ty_vars(&self, n: usize) -> Vec> { - (0..n).map(|_i| self.next_ty_var()).collect() - } - - pub fn next_int_var_id(&self) -> IntVid { - self.int_unification_table - .borrow_mut() - .new_key(None) - } - - pub fn next_float_var_id(&self) -> FloatVid { - self.float_unification_table - .borrow_mut() - .new_key(None) - } - - pub fn next_region_var(&self, origin: RegionVariableOrigin) -> ty::Region { - ty::ReVar(self.region_vars.new_region_var(origin)) - } - - pub fn region_vars_for_defs(&self, - span: Span, - defs: &[ty::RegionParameterDef]) - -> Vec { - defs.iter() - .map(|d| self.next_region_var(EarlyBoundRegion(span, d.name))) - .collect() - } - - // We have to take `&mut Substs` in order to provide the correct substitutions for defaults - // along the way, for this reason we don't return them. - pub fn type_vars_for_defs(&self, - span: Span, - space: subst::ParamSpace, - substs: &mut Substs<'tcx>, - defs: &[ty::TypeParameterDef<'tcx>]) { - - for def in defs.iter() { - let default = def.default.map(|default| { - type_variable::Default { - ty: default.subst_spanned(self.tcx, substs, Some(span)), - origin_span: span, - def_id: def.default_def_id - } - }); - - let ty_var = self.next_ty_var_with_default(default); - substs.types.push(space, ty_var); - } - } - - /// Given a set of generics defined on a type or impl, returns a substitution mapping each - /// type/region parameter to a fresh inference variable. - pub fn fresh_substs_for_generics(&self, - span: Span, - generics: &ty::Generics<'tcx>) - -> subst::Substs<'tcx> - { - let type_params = subst::VecPerParamSpace::empty(); - - let region_params = - generics.regions.map( - |d| self.next_region_var(EarlyBoundRegion(span, d.name))); - - let mut substs = subst::Substs::new(type_params, region_params); - - for space in subst::ParamSpace::all().iter() { - self.type_vars_for_defs( - span, - *space, - &mut substs, - generics.types.get_slice(*space)); - } - - return substs; - } - - /// Given a set of generics defined on a trait, returns a substitution mapping each output - /// type/region parameter to a fresh inference variable, and mapping the self type to - /// `self_ty`. - pub fn fresh_substs_for_trait(&self, - span: Span, - generics: &ty::Generics<'tcx>, - self_ty: Ty<'tcx>) - -> subst::Substs<'tcx> - { - - assert!(generics.types.len(subst::SelfSpace) == 1); - assert!(generics.types.len(subst::FnSpace) == 0); - assert!(generics.regions.len(subst::SelfSpace) == 0); - assert!(generics.regions.len(subst::FnSpace) == 0); - - let type_params = Vec::new(); - - let region_param_defs = generics.regions.get_slice(subst::TypeSpace); - let regions = self.region_vars_for_defs(span, region_param_defs); - - let mut substs = subst::Substs::new_trait(type_params, regions, self_ty); - - let type_parameter_defs = generics.types.get_slice(subst::TypeSpace); - self.type_vars_for_defs(span, subst::TypeSpace, &mut substs, type_parameter_defs); - - return substs; - } - - pub fn fresh_bound_region(&self, debruijn: ty::DebruijnIndex) -> ty::Region { - self.region_vars.new_bound(debruijn) - } - - /// Apply `adjustment` to the type of `expr` - pub fn adjust_expr_ty(&self, - expr: &hir::Expr, - adjustment: Option<&adjustment::AutoAdjustment<'tcx>>) - -> Ty<'tcx> - { - let raw_ty = self.expr_ty(expr); - let raw_ty = self.shallow_resolve(raw_ty); - let resolve_ty = |ty: Ty<'tcx>| self.resolve_type_vars_if_possible(&ty); - raw_ty.adjust(self.tcx, - expr.span, - expr.id, - adjustment, - |method_call| self.tables - .borrow() - .method_map - .get(&method_call) - .map(|method| resolve_ty(method.ty))) - } - - pub fn errors_since_creation(&self) -> bool { - self.tcx.sess.err_count() - self.err_count_on_creation != 0 - } - - pub fn node_type(&self, id: ast::NodeId) -> Ty<'tcx> { - match self.tables.borrow().node_types.get(&id) { - Some(&t) => t, - // FIXME - None if self.errors_since_creation() => - self.tcx.types.err, - None => { - self.tcx.sess.bug( - &format!("no type for node {}: {} in fcx", - id, self.tcx.map.node_to_string(id))); - } - } - } - - pub fn expr_ty(&self, ex: &hir::Expr) -> Ty<'tcx> { - match self.tables.borrow().node_types.get(&ex.id) { - Some(&t) => t, - None => { - self.tcx.sess.bug("no type for expr in fcx"); - } - } - } - - pub fn resolve_regions_and_report_errors(&self, - free_regions: &FreeRegionMap, - subject_node_id: ast::NodeId) { - let errors = self.region_vars.resolve_regions(free_regions, subject_node_id); - if !self.errors_since_creation() { - // As a heuristic, just skip reporting region errors - // altogether if other errors have been reported while - // this infcx was in use. This is totally hokey but - // otherwise we have a hard time separating legit region - // errors from silly ones. - self.report_region_errors(&errors); // see error_reporting.rs - } - } - - pub fn ty_to_string(&self, t: Ty<'tcx>) -> String { - self.resolve_type_vars_if_possible(&t).to_string() - } - - pub fn tys_to_string(&self, ts: &[Ty<'tcx>]) -> String { - let tstrs: Vec = ts.iter().map(|t| self.ty_to_string(*t)).collect(); - format!("({})", tstrs.join(", ")) - } - - pub fn trait_ref_to_string(&self, t: &ty::TraitRef<'tcx>) -> String { - self.resolve_type_vars_if_possible(t).to_string() - } - - pub fn shallow_resolve(&self, typ: Ty<'tcx>) -> Ty<'tcx> { - match typ.sty { - ty::TyInfer(ty::TyVar(v)) => { - // Not entirely obvious: if `typ` is a type variable, - // it can be resolved to an int/float variable, which - // can then be recursively resolved, hence the - // recursion. Note though that we prevent type - // variables from unifying to other type variables - // directly (though they may be embedded - // structurally), and we prevent cycles in any case, - // so this recursion should always be of very limited - // depth. - self.type_variables.borrow_mut() - .probe(v) - .map(|t| self.shallow_resolve(t)) - .unwrap_or(typ) - } - - ty::TyInfer(ty::IntVar(v)) => { - self.int_unification_table - .borrow_mut() - .probe(v) - .map(|v| v.to_type(self.tcx)) - .unwrap_or(typ) - } - - ty::TyInfer(ty::FloatVar(v)) => { - self.float_unification_table - .borrow_mut() - .probe(v) - .map(|v| v.to_type(self.tcx)) - .unwrap_or(typ) - } - - _ => { - typ - } - } - } - - pub fn resolve_type_vars_if_possible(&self, value: &T) -> T - where T: TypeFoldable<'tcx> - { - /*! - * Where possible, replaces type/int/float variables in - * `value` with their final value. Note that region variables - * are unaffected. If a type variable has not been unified, it - * is left as is. This is an idempotent operation that does - * not affect inference state in any way and so you can do it - * at will. - */ - - if !value.needs_infer() { - return value.clone(); // avoid duplicated subst-folding - } - let mut r = resolve::OpportunisticTypeResolver::new(self); - value.fold_with(&mut r) - } - - pub fn resolve_type_and_region_vars_if_possible(&self, value: &T) -> T - where T: TypeFoldable<'tcx> - { - let mut r = resolve::OpportunisticTypeAndRegionResolver::new(self); - value.fold_with(&mut r) - } - - /// Resolves all type variables in `t` and then, if any were left - /// unresolved, substitutes an error type. This is used after the - /// main checking when doing a second pass before writeback. The - /// justification is that writeback will produce an error for - /// these unconstrained type variables. - fn resolve_type_vars_or_error(&self, t: &Ty<'tcx>) -> mc::McResult> { - let ty = self.resolve_type_vars_if_possible(t); - if ty.references_error() || ty.is_ty_var() { - debug!("resolve_type_vars_or_error: error from {:?}", ty); - Err(()) - } else { - Ok(ty) - } - } - - pub fn fully_resolve>(&self, value: &T) -> FixupResult { - /*! - * Attempts to resolve all type/region variables in - * `value`. Region inference must have been run already (e.g., - * by calling `resolve_regions_and_report_errors`). If some - * variable was never unified, an `Err` results. - * - * This method is idempotent, but it not typically not invoked - * except during the writeback phase. - */ - - resolve::fully_resolve(self, value) - } - - // [Note-Type-error-reporting] - // An invariant is that anytime the expected or actual type is TyError (the special - // error type, meaning that an error occurred when typechecking this expression), - // this is a derived error. The error cascaded from another error (that was already - // reported), so it's not useful to display it to the user. - // The following four methods -- type_error_message_str, type_error_message_str_with_expected, - // type_error_message, and report_mismatched_types -- implement this logic. - // They check if either the actual or expected type is TyError, and don't print the error - // in this case. The typechecker should only ever report type errors involving mismatched - // types using one of these four methods, and should not call span_err directly for such - // errors. - pub fn type_error_message_str(&self, - sp: Span, - mk_msg: M, - actual_ty: String, - err: Option<&TypeError<'tcx>>) - where M: FnOnce(Option, String) -> String, - { - self.type_error_message_str_with_expected(sp, mk_msg, None, actual_ty, err) - } - - pub fn type_error_struct_str(&self, - sp: Span, - mk_msg: M, - actual_ty: String, - err: Option<&TypeError<'tcx>>) - -> DiagnosticBuilder<'tcx> - where M: FnOnce(Option, String) -> String, - { - self.type_error_struct_str_with_expected(sp, mk_msg, None, actual_ty, err) - } - - pub fn type_error_message_str_with_expected(&self, - sp: Span, - mk_msg: M, - expected_ty: Option>, - actual_ty: String, - err: Option<&TypeError<'tcx>>) - where M: FnOnce(Option, String) -> String, - { - self.type_error_struct_str_with_expected(sp, mk_msg, expected_ty, actual_ty, err) - .emit(); - } - - pub fn type_error_struct_str_with_expected(&self, - sp: Span, - mk_msg: M, - expected_ty: Option>, - actual_ty: String, - err: Option<&TypeError<'tcx>>) - -> DiagnosticBuilder<'tcx> - where M: FnOnce(Option, String) -> String, - { - debug!("hi! expected_ty = {:?}, actual_ty = {}", expected_ty, actual_ty); - - let resolved_expected = expected_ty.map(|e_ty| self.resolve_type_vars_if_possible(&e_ty)); - - if !resolved_expected.references_error() { - let error_str = err.map_or("".to_string(), |t_err| { - format!(" ({})", t_err) - }); - - let mut db = self.tcx.sess.struct_span_err(sp, &format!("{}{}", - mk_msg(resolved_expected.map(|t| self.ty_to_string(t)), actual_ty), - error_str)); - - if let Some(err) = err { - self.tcx.note_and_explain_type_err(&mut db, err, sp); - } - db - } else { - self.tcx.sess.diagnostic().struct_dummy() - } - } - - pub fn type_error_message(&self, - sp: Span, - mk_msg: M, - actual_ty: Ty<'tcx>, - err: Option<&TypeError<'tcx>>) - where M: FnOnce(String) -> String, - { - self.type_error_struct(sp, mk_msg, actual_ty, err).emit(); - } - - pub fn type_error_struct(&self, - sp: Span, - mk_msg: M, - actual_ty: Ty<'tcx>, - err: Option<&TypeError<'tcx>>) - -> DiagnosticBuilder<'tcx> - where M: FnOnce(String) -> String, - { - let actual_ty = self.resolve_type_vars_if_possible(&actual_ty); - - // Don't report an error if actual type is TyError. - if actual_ty.references_error() { - return self.tcx.sess.diagnostic().struct_dummy(); - } - - self.type_error_struct_str(sp, - move |_e, a| { mk_msg(a) }, - self.ty_to_string(actual_ty), err) - } - - pub fn report_mismatched_types(&self, - origin: TypeOrigin, - expected: Ty<'tcx>, - actual: Ty<'tcx>, - err: TypeError<'tcx>) { - let trace = TypeTrace { - origin: origin, - values: Types(ExpectedFound { - expected: expected, - found: actual - }) - }; - self.report_and_explain_type_error(trace, &err).emit(); - } - - pub fn report_conflicting_default_types(&self, - span: Span, - expected: type_variable::Default<'tcx>, - actual: type_variable::Default<'tcx>) { - let trace = TypeTrace { - origin: TypeOrigin::Misc(span), - values: Types(ExpectedFound { - expected: expected.ty, - found: actual.ty - }) - }; - - self.report_and_explain_type_error( - trace, - &TypeError::TyParamDefaultMismatch(ExpectedFound { - expected: expected, - found: actual - })) - .emit(); - } - - pub fn replace_late_bound_regions_with_fresh_var( - &self, - span: Span, - lbrct: LateBoundRegionConversionTime, - value: &ty::Binder) - -> (T, FnvHashMap) - where T : TypeFoldable<'tcx> - { - self.tcx.replace_late_bound_regions( - value, - |br| self.next_region_var(LateBoundRegion(span, br, lbrct))) - } - - /// See `verify_generic_bound` method in `region_inference` - pub fn verify_generic_bound(&self, - origin: SubregionOrigin<'tcx>, - kind: GenericKind<'tcx>, - a: ty::Region, - bound: VerifyBound) { - debug!("verify_generic_bound({:?}, {:?} <: {:?})", - kind, - a, - bound); - - self.region_vars.verify_generic_bound(origin, kind, a, bound); - } - - pub fn can_equate<'b,T>(&'b self, a: &T, b: &T) -> UnitResult<'tcx> - where T: Relate<'b,'tcx> + fmt::Debug - { - debug!("can_equate({:?}, {:?})", a, b); - self.probe(|_| { - // Gin up a dummy trace, since this won't be committed - // anyhow. We should make this typetrace stuff more - // generic so we don't have to do anything quite this - // terrible. - let e = self.tcx.types.err; - let trace = TypeTrace { - origin: TypeOrigin::Misc(codemap::DUMMY_SP), - values: Types(expected_found(true, e, e)) - }; - self.equate(true, trace).relate(a, b) - }).map(|_| ()) - } - - pub fn node_ty(&self, id: ast::NodeId) -> McResult> { - let ty = self.node_type(id); - self.resolve_type_vars_or_error(&ty) - } - - pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> McResult> { - let ty = self.adjust_expr_ty(expr, self.tables.borrow().adjustments.get(&expr.id)); - self.resolve_type_vars_or_error(&ty) - } - - pub fn tables_are_tcx_tables(&self) -> bool { - let tables: &RefCell = &self.tables; - let tcx_tables: &RefCell = &self.tcx.tables; - tables as *const _ == tcx_tables as *const _ - } - - pub fn type_moves_by_default(&self, ty: Ty<'tcx>, span: Span) -> bool { - let ty = self.resolve_type_vars_if_possible(&ty); - if ty.needs_infer() || - (ty.has_closure_types() && !self.tables_are_tcx_tables()) { - // this can get called from typeck (by euv), and moves_by_default - // rightly refuses to work with inference variables, but - // moves_by_default has a cache, which we want to use in other - // cases. - !traits::type_known_to_meet_builtin_bound(self, ty, ty::BoundCopy, span) - } else { - ty.moves_by_default(&self.parameter_environment, span) - } - } - - pub fn node_method_ty(&self, method_call: ty::MethodCall) - -> Option> { - self.tables - .borrow() - .method_map - .get(&method_call) - .map(|method| method.ty) - .map(|ty| self.resolve_type_vars_if_possible(&ty)) - } - - pub fn node_method_id(&self, method_call: ty::MethodCall) - -> Option { - self.tables - .borrow() - .method_map - .get(&method_call) - .map(|method| method.def_id) - } - - pub fn adjustments(&self) -> Ref>> { - fn project_adjustments<'a, 'tcx>(tables: &'a ty::Tables<'tcx>) - -> &'a NodeMap> { - &tables.adjustments - } - - Ref::map(self.tables.borrow(), project_adjustments) - } - - pub fn is_method_call(&self, id: ast::NodeId) -> bool { - self.tables.borrow().method_map.contains_key(&ty::MethodCall::expr(id)) - } - - pub fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option { - self.tcx.region_maps.temporary_scope(rvalue_id) - } - - pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option { - self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned() - } - - pub fn param_env<'b>(&'b self) -> &'b ty::ParameterEnvironment<'b,'tcx> { - &self.parameter_environment - } - - pub fn closure_kind(&self, - def_id: DefId) - -> Option - { - if def_id.is_local() { - self.tables.borrow().closure_kinds.get(&def_id).cloned() - } else { - // During typeck, ALL closures are local. But afterwards, - // during trans, we see closure ids from other traits. - // That may require loading the closure data out of the - // cstore. - Some(ty::Tables::closure_kind(&self.tables, self.tcx, def_id)) - } - } - - pub fn closure_type(&self, - def_id: DefId, - substs: &ty::ClosureSubsts<'tcx>) - -> ty::ClosureTy<'tcx> - { - let closure_ty = - ty::Tables::closure_type(self.tables, - self.tcx, - def_id, - substs); - - if self.normalize { - normalize_associated_type(&self.tcx, &closure_ty) - } else { - closure_ty - } - } -} - -impl<'tcx> TypeTrace<'tcx> { - pub fn span(&self) -> Span { - self.origin.span() - } - - pub fn types(origin: TypeOrigin, - a_is_expected: bool, - a: Ty<'tcx>, - b: Ty<'tcx>) - -> TypeTrace<'tcx> { - TypeTrace { - origin: origin, - values: Types(expected_found(a_is_expected, a, b)) - } - } - - pub fn dummy(tcx: &TyCtxt<'tcx>) -> TypeTrace<'tcx> { - TypeTrace { - origin: TypeOrigin::Misc(codemap::DUMMY_SP), - values: Types(ExpectedFound { - expected: tcx.types.err, - found: tcx.types.err, - }) - } - } -} - -impl<'tcx> fmt::Debug for TypeTrace<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "TypeTrace({:?})", self.origin) - } -} - -impl TypeOrigin { - pub fn span(&self) -> Span { - match *self { - TypeOrigin::MethodCompatCheck(span) => span, - TypeOrigin::ExprAssignable(span) => span, - TypeOrigin::Misc(span) => span, - TypeOrigin::RelateTraitRefs(span) => span, - TypeOrigin::RelateSelfType(span) => span, - TypeOrigin::RelateOutputImplTypes(span) => span, - TypeOrigin::MatchExpressionArm(match_span, _, _) => match_span, - TypeOrigin::IfExpression(span) => span, - TypeOrigin::IfExpressionWithNoElse(span) => span, - TypeOrigin::RangeExpression(span) => span, - TypeOrigin::EquatePredicate(span) => span, - } - } -} - -impl<'tcx> SubregionOrigin<'tcx> { - pub fn span(&self) -> Span { - match *self { - Subtype(ref a) => a.span(), - InfStackClosure(a) => a, - InvokeClosure(a) => a, - DerefPointer(a) => a, - FreeVariable(a, _) => a, - IndexSlice(a) => a, - RelateObjectBound(a) => a, - RelateParamBound(a, _) => a, - RelateRegionParamBound(a) => a, - RelateDefaultParamBound(a, _) => a, - Reborrow(a) => a, - ReborrowUpvar(a, _) => a, - DataBorrowed(_, a) => a, - ReferenceOutlivesReferent(_, a) => a, - ParameterInScope(_, a) => a, - ExprTypeIsNotInScope(_, a) => a, - BindingTypeIsNotValidAtDecl(a) => a, - CallRcvr(a) => a, - CallArg(a) => a, - CallReturn(a) => a, - Operand(a) => a, - AddrOf(a) => a, - AutoBorrow(a) => a, - SafeDestructor(a) => a, - } - } -} - -impl RegionVariableOrigin { - pub fn span(&self) -> Span { - match *self { - MiscVariable(a) => a, - PatternRegion(a) => a, - AddrOfRegion(a) => a, - Autoref(a) => a, - Coercion(a) => a, - EarlyBoundRegion(a, _) => a, - LateBoundRegion(a, _, _) => a, - BoundRegionInCoherence(_) => codemap::DUMMY_SP, - UpvarRegion(_, a) => a - } - } -} diff --git a/src/librustc/middle/infer/region_inference/README.md b/src/librustc/middle/infer/region_inference/README.md deleted file mode 100644 index 80da861139b..00000000000 --- a/src/librustc/middle/infer/region_inference/README.md +++ /dev/null @@ -1,311 +0,0 @@ -Region inference - -# Terminology - -Note that we use the terms region and lifetime interchangeably. - -# Introduction - -Region inference uses a somewhat more involved algorithm than type -inference. It is not the most efficient thing ever written though it -seems to work well enough in practice (famous last words). The reason -that we use a different algorithm is because, unlike with types, it is -impractical to hand-annotate with regions (in some cases, there aren't -even the requisite syntactic forms). So we have to get it right, and -it's worth spending more time on a more involved analysis. Moreover, -regions are a simpler case than types: they don't have aggregate -structure, for example. - -Unlike normal type inference, which is similar in spirit to H-M and thus -works progressively, the region type inference works by accumulating -constraints over the course of a function. Finally, at the end of -processing a function, we process and solve the constraints all at -once. - -The constraints are always of one of three possible forms: - -- `ConstrainVarSubVar(Ri, Rj)` states that region variable Ri must be - a subregion of Rj -- `ConstrainRegSubVar(R, Ri)` states that the concrete region R (which - must not be a variable) must be a subregion of the variable Ri -- `ConstrainVarSubReg(Ri, R)` states the variable Ri shoudl be less - than the concrete region R. This is kind of deprecated and ought to - be replaced with a verify (they essentially play the same role). - -In addition to constraints, we also gather up a set of "verifys" -(what, you don't think Verify is a noun? Get used to it my -friend!). These represent relations that must hold but which don't -influence inference proper. These take the form of: - -- `VerifyRegSubReg(Ri, Rj)` indicates that Ri <= Rj must hold, - where Rj is not an inference variable (and Ri may or may not contain - one). This doesn't influence inference because we will already have - inferred Ri to be as small as possible, so then we just test whether - that result was less than Rj or not. -- `VerifyGenericBound(R, Vb)` is a more complex expression which tests - that the region R must satisfy the bound `Vb`. The bounds themselves - may have structure like "must outlive one of the following regions" - or "must outlive ALL of the following regions. These bounds arise - from constraints like `T: 'a` -- if we know that `T: 'b` and `T: 'c` - (say, from where clauses), then we can conclude that `T: 'a` if `'b: - 'a` *or* `'c: 'a`. - -# Building up the constraints - -Variables and constraints are created using the following methods: - -- `new_region_var()` creates a new, unconstrained region variable; -- `make_subregion(Ri, Rj)` states that Ri is a subregion of Rj -- `lub_regions(Ri, Rj) -> Rk` returns a region Rk which is - the smallest region that is greater than both Ri and Rj -- `glb_regions(Ri, Rj) -> Rk` returns a region Rk which is - the greatest region that is smaller than both Ri and Rj - -The actual region resolution algorithm is not entirely -obvious, though it is also not overly complex. - -## Snapshotting - -It is also permitted to try (and rollback) changes to the graph. This -is done by invoking `start_snapshot()`, which returns a value. Then -later you can call `rollback_to()` which undoes the work. -Alternatively, you can call `commit()` which ends all snapshots. -Snapshots can be recursive---so you can start a snapshot when another -is in progress, but only the root snapshot can "commit". - -## The problem - -Basically our input is a directed graph where nodes can be divided -into two categories: region variables and concrete regions. Each edge -`R -> S` in the graph represents a constraint that the region `R` is a -subregion of the region `S`. - -Region variable nodes can have arbitrary degree. There is one region -variable node per region variable. - -Each concrete region node is associated with some, well, concrete -region: e.g., a free lifetime, or the region for a particular scope. -Note that there may be more than one concrete region node for a -particular region value. Moreover, because of how the graph is built, -we know that all concrete region nodes have either in-degree 1 or -out-degree 1. - -Before resolution begins, we build up the constraints in a hashmap -that maps `Constraint` keys to spans. During resolution, we construct -the actual `Graph` structure that we describe here. - -## Computing the values for region variables - -The algorithm is a simple dataflow algorithm. Each region variable -begins as empty. We iterate over the constraints, and for each constraint -we grow the relevant region variable to be as big as it must be to meet all the -constraints. This means the region variables can grow to be `'static` if -necessary. - -## Verification - -After all constraints are fully propoagated, we do a "verification" -step where we walk over the verify bounds and check that they are -satisfied. These bounds represent the "maximal" values that a region -variable can take on, basically. - -# The Region Hierarchy - -## Without closures - -Let's first consider the region hierarchy without thinking about -closures, because they add a lot of complications. The region -hierarchy *basically* mirrors the lexical structure of the code. -There is a region for every piece of 'evaluation' that occurs, meaning -every expression, block, and pattern (patterns are considered to -"execute" by testing the value they are applied to and creating any -relevant bindings). So, for example: - - fn foo(x: isize, y: isize) { // -+ - // +------------+ // | - // | +-----+ // | - // | +-+ +-+ +-+ // | - // | | | | | | | // | - // v v v v v v v // | - let z = x + y; // | - ... // | - } // -+ - - fn bar() { ... } - -In this example, there is a region for the fn body block as a whole, -and then a subregion for the declaration of the local variable. -Within that, there are sublifetimes for the assignment pattern and -also the expression `x + y`. The expression itself has sublifetimes -for evaluating `x` and `y`. - -## Function calls - -Function calls are a bit tricky. I will describe how we handle them -*now* and then a bit about how we can improve them (Issue #6268). - -Consider a function call like `func(expr1, expr2)`, where `func`, -`arg1`, and `arg2` are all arbitrary expressions. Currently, -we construct a region hierarchy like: - - +----------------+ - | | - +--+ +---+ +---+| - v v v v v vv - func(expr1, expr2) - -Here you can see that the call as a whole has a region and the -function plus arguments are subregions of that. As a side-effect of -this, we get a lot of spurious errors around nested calls, in -particular when combined with `&mut` functions. For example, a call -like this one - - self.foo(self.bar()) - -where both `foo` and `bar` are `&mut self` functions will always yield -an error. - -Here is a more involved example (which is safe) so we can see what's -going on: - - struct Foo { f: usize, g: usize } - ... - fn add(p: &mut usize, v: usize) { - *p += v; - } - ... - fn inc(p: &mut usize) -> usize { - *p += 1; *p - } - fn weird() { - let mut x: Box = box Foo { ... }; - 'a: add(&mut (*x).f, - 'b: inc(&mut (*x).f)) // (..) - } - -The important part is the line marked `(..)` which contains a call to -`add()`. The first argument is a mutable borrow of the field `f`. The -second argument also borrows the field `f`. Now, in the current borrow -checker, the first borrow is given the lifetime of the call to -`add()`, `'a`. The second borrow is given the lifetime of `'b` of the -call to `inc()`. Because `'b` is considered to be a sublifetime of -`'a`, an error is reported since there are two co-existing mutable -borrows of the same data. - -However, if we were to examine the lifetimes a bit more carefully, we -can see that this error is unnecessary. Let's examine the lifetimes -involved with `'a` in detail. We'll break apart all the steps involved -in a call expression: - - 'a: { - 'a_arg1: let a_temp1: ... = add; - 'a_arg2: let a_temp2: &'a mut usize = &'a mut (*x).f; - 'a_arg3: let a_temp3: usize = { - let b_temp1: ... = inc; - let b_temp2: &'b = &'b mut (*x).f; - 'b_call: b_temp1(b_temp2) - }; - 'a_call: a_temp1(a_temp2, a_temp3) // (**) - } - -Here we see that the lifetime `'a` includes a number of substatements. -In particular, there is this lifetime I've called `'a_call` that -corresponds to the *actual execution of the function `add()`*, after -all arguments have been evaluated. There is a corresponding lifetime -`'b_call` for the execution of `inc()`. If we wanted to be precise -about it, the lifetime of the two borrows should be `'a_call` and -`'b_call` respectively, since the references that were created -will not be dereferenced except during the execution itself. - -However, this model by itself is not sound. The reason is that -while the two references that are created will never be used -simultaneously, it is still true that the first reference is -*created* before the second argument is evaluated, and so even though -it will not be *dereferenced* during the evaluation of the second -argument, it can still be *invalidated* by that evaluation. Consider -this similar but unsound example: - - struct Foo { f: usize, g: usize } - ... - fn add(p: &mut usize, v: usize) { - *p += v; - } - ... - fn consume(x: Box) -> usize { - x.f + x.g - } - fn weird() { - let mut x: Box = box Foo { ... }; - 'a: add(&mut (*x).f, consume(x)) // (..) - } - -In this case, the second argument to `add` actually consumes `x`, thus -invalidating the first argument. - -So, for now, we exclude the `call` lifetimes from our model. -Eventually I would like to include them, but we will have to make the -borrow checker handle this situation correctly. In particular, if -there is a reference created whose lifetime does not enclose -the borrow expression, we must issue sufficient restrictions to ensure -that the pointee remains valid. - -## Modeling closures - -Integrating closures properly into the model is a bit of -work-in-progress. In an ideal world, we would model closures as -closely as possible after their desugared equivalents. That is, a -closure type would be modeled as a struct, and the region hierarchy of -different closure bodies would be completely distinct from all other -fns. We are generally moving in that direction but there are -complications in terms of the implementation. - -In practice what we currently do is somewhat different. The basis for -the current approach is the observation that the only time that -regions from distinct fn bodies interact with one another is through -an upvar or the type of a fn parameter (since closures live in the fn -body namespace, they can in fact have fn parameters whose types -include regions from the surrounding fn body). For these cases, there -are separate mechanisms which ensure that the regions that appear in -upvars/parameters outlive the dynamic extent of each call to the -closure: - -1. Types must outlive the region of any expression where they are used. - For a closure type `C` to outlive a region `'r`, that implies that the - types of all its upvars must outlive `'r`. -2. Parameters must outlive the region of any fn that they are passed to. - -Therefore, we can -- sort of -- assume that any region from an -enclosing fns is larger than any region from one of its enclosed -fn. And that is precisely what we do: when building the region -hierarchy, each region lives in its own distinct subtree, but if we -are asked to compute the `LUB(r1, r2)` of two regions, and those -regions are in disjoint subtrees, we compare the lexical nesting of -the two regions. - -*Ideas for improving the situation:* (FIXME #3696) The correctness -argument here is subtle and a bit hand-wavy. The ideal, as stated -earlier, would be to model things in such a way that it corresponds -more closely to the desugared code. The best approach for doing this -is a bit unclear: it may in fact be possible to *actually* desugar -before we start, but I don't think so. The main option that I've been -thinking through is imposing a "view shift" as we enter the fn body, -so that regions appearing in the types of fn parameters and upvars are -translated from being regions in the outer fn into free region -parameters, just as they would be if we applied the desugaring. The -challenge here is that type inference may not have fully run, so the -types may not be fully known: we could probably do this translation -lazilly, as type variables are instantiated. We would also have to -apply a kind of inverse translation to the return value. This would be -a good idea anyway, as right now it is possible for free regions -instantiated within the closure to leak into the parent: this -currently leads to type errors, since those regions cannot outlive any -expressions within the parent hierarchy. Much like the current -handling of closures, there are no known cases where this leads to a -type-checking accepting incorrect code (though it sometimes rejects -what might be considered correct code; see rust-lang/rust#22557), but -it still doesn't feel like the right approach. - -### Skolemization - -For a discussion on skolemization and higher-ranked subtyping, please -see the module `middle::infer::higher_ranked::doc`. diff --git a/src/librustc/middle/infer/region_inference/graphviz.rs b/src/librustc/middle/infer/region_inference/graphviz.rs deleted file mode 100644 index 23559e7b340..00000000000 --- a/src/librustc/middle/infer/region_inference/graphviz.rs +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright 2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! This module provides linkage between libgraphviz traits and -//! `rustc::middle::typeck::infer::region_inference`, generating a -//! rendering of the graph represented by the list of `Constraint` -//! instances (which make up the edges of the graph), as well as the -//! origin for each constraint (which are attached to the labels on -//! each edge). - -/// For clarity, rename the graphviz crate locally to dot. -use graphviz as dot; - -use middle::ty::{self, TyCtxt}; -use middle::region::CodeExtent; -use super::Constraint; -use middle::infer::SubregionOrigin; -use middle::infer::region_inference::RegionVarBindings; -use util::nodemap::{FnvHashMap, FnvHashSet}; - -use std::borrow::Cow; -use std::collections::hash_map::Entry::Vacant; -use std::env; -use std::fs::File; -use std::io; -use std::io::prelude::*; -use std::sync::atomic::{AtomicBool, Ordering}; -use syntax::ast; - -fn print_help_message() { - println!("\ --Z print-region-graph by default prints a region constraint graph for every \n\ -function body, to the path `/tmp/constraints.nodeXXX.dot`, where the XXX is \n\ -replaced with the node id of the function under analysis. \n\ - \n\ -To select one particular function body, set `RUST_REGION_GRAPH_NODE=XXX`, \n\ -where XXX is the node id desired. \n\ - \n\ -To generate output to some path other than the default \n\ -`/tmp/constraints.nodeXXX.dot`, set `RUST_REGION_GRAPH=/path/desired.dot`; \n\ -occurrences of the character `%` in the requested path will be replaced with\n\ -the node id of the function under analysis. \n\ - \n\ -(Since you requested help via RUST_REGION_GRAPH=help, no region constraint \n\ -graphs will be printed. \n\ -"); -} - -pub fn maybe_print_constraints_for<'a, 'tcx>(region_vars: &RegionVarBindings<'a, 'tcx>, - subject_node: ast::NodeId) { - let tcx = region_vars.tcx; - - if !region_vars.tcx.sess.opts.debugging_opts.print_region_graph { - return; - } - - let requested_node: Option = env::var("RUST_REGION_GRAPH_NODE") - .ok() - .and_then(|s| s.parse().ok()); - - if requested_node.is_some() && requested_node != Some(subject_node) { - return; - } - - let requested_output = env::var("RUST_REGION_GRAPH"); - debug!("requested_output: {:?} requested_node: {:?}", - requested_output, - requested_node); - - let output_path = { - let output_template = match requested_output { - Ok(ref s) if s == "help" => { - static PRINTED_YET: AtomicBool = AtomicBool::new(false); - if !PRINTED_YET.load(Ordering::SeqCst) { - print_help_message(); - PRINTED_YET.store(true, Ordering::SeqCst); - } - return; - } - - Ok(other_path) => other_path, - Err(_) => "/tmp/constraints.node%.dot".to_string(), - }; - - if output_template.is_empty() { - tcx.sess.bug("empty string provided as RUST_REGION_GRAPH"); - } - - if output_template.contains('%') { - let mut new_str = String::new(); - for c in output_template.chars() { - if c == '%' { - new_str.push_str(&subject_node.to_string()); - } else { - new_str.push(c); - } - } - new_str - } else { - output_template - } - }; - - let constraints = &*region_vars.constraints.borrow(); - match dump_region_constraints_to(tcx, constraints, &output_path) { - Ok(()) => {} - Err(e) => { - let msg = format!("io error dumping region constraints: {}", e); - region_vars.tcx.sess.err(&msg) - } - } -} - -struct ConstraintGraph<'a, 'tcx: 'a> { - tcx: &'a TyCtxt<'tcx>, - graph_name: String, - map: &'a FnvHashMap>, - node_ids: FnvHashMap, -} - -#[derive(Clone, Hash, PartialEq, Eq, Debug, Copy)] -enum Node { - RegionVid(ty::RegionVid), - Region(ty::Region), -} - -// type Edge = Constraint; -#[derive(Clone, PartialEq, Eq, Debug, Copy)] -enum Edge { - Constraint(Constraint), - EnclScope(CodeExtent, CodeExtent), -} - -impl<'a, 'tcx> ConstraintGraph<'a, 'tcx> { - fn new(tcx: &'a TyCtxt<'tcx>, - name: String, - map: &'a ConstraintMap<'tcx>) - -> ConstraintGraph<'a, 'tcx> { - let mut i = 0; - let mut node_ids = FnvHashMap(); - { - let mut add_node = |node| { - if let Vacant(e) = node_ids.entry(node) { - e.insert(i); - i += 1; - } - }; - - for (n1, n2) in map.keys().map(|c| constraint_to_nodes(c)) { - add_node(n1); - add_node(n2); - } - - tcx.region_maps.each_encl_scope(|sub, sup| { - add_node(Node::Region(ty::ReScope(*sub))); - add_node(Node::Region(ty::ReScope(*sup))); - }); - } - - ConstraintGraph { - tcx: tcx, - graph_name: name, - map: map, - node_ids: node_ids, - } - } -} - -impl<'a, 'tcx> dot::Labeller<'a> for ConstraintGraph<'a, 'tcx> { - type Node = Node; - type Edge = Edge; - fn graph_id(&self) -> dot::Id { - dot::Id::new(&*self.graph_name).unwrap() - } - fn node_id(&self, n: &Node) -> dot::Id { - let node_id = match self.node_ids.get(n) { - Some(node_id) => node_id, - None => panic!("no node_id found for node: {:?}", n), - }; - let name = || format!("node_{}", node_id); - match dot::Id::new(name()) { - Ok(id) => id, - Err(_) => { - panic!("failed to create graphviz node identified by {}", name()); - } - } - } - fn node_label(&self, n: &Node) -> dot::LabelText { - match *n { - Node::RegionVid(n_vid) => dot::LabelText::label(format!("{:?}", n_vid)), - Node::Region(n_rgn) => dot::LabelText::label(format!("{:?}", n_rgn)), - } - } - fn edge_label(&self, e: &Edge) -> dot::LabelText { - match *e { - Edge::Constraint(ref c) => - dot::LabelText::label(format!("{:?}", self.map.get(c).unwrap())), - Edge::EnclScope(..) => dot::LabelText::label(format!("(enclosed)")), - } - } -} - -fn constraint_to_nodes(c: &Constraint) -> (Node, Node) { - match *c { - Constraint::ConstrainVarSubVar(rv_1, rv_2) => - (Node::RegionVid(rv_1), Node::RegionVid(rv_2)), - Constraint::ConstrainRegSubVar(r_1, rv_2) => (Node::Region(r_1), Node::RegionVid(rv_2)), - Constraint::ConstrainVarSubReg(rv_1, r_2) => (Node::RegionVid(rv_1), Node::Region(r_2)), - } -} - -fn edge_to_nodes(e: &Edge) -> (Node, Node) { - match *e { - Edge::Constraint(ref c) => constraint_to_nodes(c), - Edge::EnclScope(sub, sup) => { - (Node::Region(ty::ReScope(sub)), - Node::Region(ty::ReScope(sup))) - } - } -} - -impl<'a, 'tcx> dot::GraphWalk<'a> for ConstraintGraph<'a, 'tcx> { - type Node = Node; - type Edge = Edge; - fn nodes(&self) -> dot::Nodes { - let mut set = FnvHashSet(); - for node in self.node_ids.keys() { - set.insert(*node); - } - debug!("constraint graph has {} nodes", set.len()); - set.into_iter().collect() - } - fn edges(&self) -> dot::Edges { - debug!("constraint graph has {} edges", self.map.len()); - let mut v: Vec<_> = self.map.keys().map(|e| Edge::Constraint(*e)).collect(); - self.tcx.region_maps.each_encl_scope(|sub, sup| v.push(Edge::EnclScope(*sub, *sup))); - debug!("region graph has {} edges", v.len()); - Cow::Owned(v) - } - fn source(&self, edge: &Edge) -> Node { - let (n1, _) = edge_to_nodes(edge); - debug!("edge {:?} has source {:?}", edge, n1); - n1 - } - fn target(&self, edge: &Edge) -> Node { - let (_, n2) = edge_to_nodes(edge); - debug!("edge {:?} has target {:?}", edge, n2); - n2 - } -} - -pub type ConstraintMap<'tcx> = FnvHashMap>; - -fn dump_region_constraints_to<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>, - map: &ConstraintMap<'tcx>, - path: &str) - -> io::Result<()> { - debug!("dump_region_constraints map (len: {}) path: {}", - map.len(), - path); - let g = ConstraintGraph::new(tcx, format!("region_constraints"), map); - debug!("dump_region_constraints calling render"); - let mut v = Vec::new(); - dot::render(&g, &mut v).unwrap(); - File::create(path).and_then(|mut f| f.write_all(&v)) -} diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs deleted file mode 100644 index 7bba495e467..00000000000 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ /dev/null @@ -1,1453 +0,0 @@ -// Copyright 2012-2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! See README.md - -pub use self::Constraint::*; -pub use self::Verify::*; -pub use self::UndoLogEntry::*; -pub use self::CombineMapType::*; -pub use self::RegionResolutionError::*; -pub use self::VarValue::*; - -use super::{RegionVariableOrigin, SubregionOrigin, MiscVariable}; -use super::unify_key; - -use rustc_data_structures::graph::{self, Direction, NodeIndex}; -use rustc_data_structures::unify::{self, UnificationTable}; -use middle::free_region::FreeRegionMap; -use middle::ty::{self, Ty, TyCtxt}; -use middle::ty::{BoundRegion, Region, RegionVid}; -use middle::ty::{ReEmpty, ReStatic, ReFree, ReEarlyBound}; -use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh}; -use util::common::indenter; -use util::nodemap::{FnvHashMap, FnvHashSet}; - -use std::cell::{Cell, RefCell}; -use std::cmp::Ordering::{self, Less, Greater, Equal}; -use std::fmt; -use std::u32; -use syntax::ast; - -mod graphviz; - -// A constraint that influences the inference process. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -pub enum Constraint { - // One region variable is subregion of another - ConstrainVarSubVar(RegionVid, RegionVid), - - // Concrete region is subregion of region variable - ConstrainRegSubVar(Region, RegionVid), - - // Region variable is subregion of concrete region - // - // FIXME(#29436) -- should be remove in favor of a Verify - ConstrainVarSubReg(RegionVid, Region), -} - -// Something we have to verify after region inference is done, but -// which does not directly influence the inference process -pub enum Verify<'tcx> { - // VerifyRegSubReg(a, b): Verify that `a <= b`. Neither `a` nor - // `b` are inference variables. - VerifyRegSubReg(SubregionOrigin<'tcx>, Region, Region), - - // VerifyGenericBound(T, _, R, RS): The parameter type `T` (or - // associated type) must outlive the region `R`. `T` is known to - // outlive `RS`. Therefore verify that `R <= RS[i]` for some - // `i`. Inference variables may be involved (but this verification - // step doesn't influence inference). - VerifyGenericBound(GenericKind<'tcx>, SubregionOrigin<'tcx>, Region, VerifyBound), -} - -#[derive(Copy, Clone, PartialEq, Eq)] -pub enum GenericKind<'tcx> { - Param(ty::ParamTy), - Projection(ty::ProjectionTy<'tcx>), -} - -// When we introduce a verification step, we wish to test that a -// particular region (let's call it `'min`) meets some bound. -// The bound is described the by the following grammar: -#[derive(Debug)] -pub enum VerifyBound { - // B = exists {R} --> some 'r in {R} must outlive 'min - // - // Put another way, the subject value is known to outlive all - // regions in {R}, so if any of those outlives 'min, then the - // bound is met. - AnyRegion(Vec), - - // B = forall {R} --> all 'r in {R} must outlive 'min - // - // Put another way, the subject value is known to outlive some - // region in {R}, so if all of those outlives 'min, then the bound - // is met. - AllRegions(Vec), - - // B = exists {B} --> 'min must meet some bound b in {B} - AnyBound(Vec), - - // B = forall {B} --> 'min must meet all bounds b in {B} - AllBounds(Vec), -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub struct TwoRegions { - a: Region, - b: Region, -} - -#[derive(Copy, Clone, PartialEq)] -pub enum UndoLogEntry { - OpenSnapshot, - CommitedSnapshot, - AddVar(RegionVid), - AddConstraint(Constraint), - AddVerify(usize), - AddGiven(ty::FreeRegion, ty::RegionVid), - AddCombination(CombineMapType, TwoRegions), -} - -#[derive(Copy, Clone, PartialEq)] -pub enum CombineMapType { - Lub, - Glb, -} - -#[derive(Clone, Debug)] -pub enum RegionResolutionError<'tcx> { - /// `ConcreteFailure(o, a, b)`: - /// - /// `o` requires that `a <= b`, but this does not hold - ConcreteFailure(SubregionOrigin<'tcx>, Region, Region), - - /// `GenericBoundFailure(p, s, a) - /// - /// The parameter/associated-type `p` must be known to outlive the lifetime - /// `a` (but none of the known bounds are sufficient). - GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region), - - /// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`: - /// - /// Could not infer a value for `v` because `sub_r <= v` (due to - /// `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and - /// `sub_r <= sup_r` does not hold. - SubSupConflict(RegionVariableOrigin, - SubregionOrigin<'tcx>, - Region, - SubregionOrigin<'tcx>, - Region), - - /// For subsets of `ConcreteFailure` and `SubSupConflict`, we can derive - /// more specific errors message by suggesting to the user where they - /// should put a lifetime. In those cases we process and put those errors - /// into `ProcessedErrors` before we do any reporting. - ProcessedErrors(Vec>, - Vec), -} - -#[derive(Clone, Debug)] -pub enum ProcessedErrorOrigin<'tcx> { - ConcreteFailure(SubregionOrigin<'tcx>, Region, Region), - VariableFailure(RegionVariableOrigin), -} - -/// SameRegions is used to group regions that we think are the same and would -/// like to indicate so to the user. -/// For example, the following function -/// ``` -/// struct Foo { bar: i32 } -/// fn foo2<'a, 'b>(x: &'a Foo) -> &'b i32 { -/// &x.bar -/// } -/// ``` -/// would report an error because we expect 'a and 'b to match, and so we group -/// 'a and 'b together inside a SameRegions struct -#[derive(Clone, Debug)] -pub struct SameRegions { - pub scope_id: ast::NodeId, - pub regions: Vec, -} - -impl SameRegions { - pub fn contains(&self, other: &BoundRegion) -> bool { - self.regions.contains(other) - } - - pub fn push(&mut self, other: BoundRegion) { - self.regions.push(other); - } -} - -pub type CombineMap = FnvHashMap; - -pub struct RegionVarBindings<'a, 'tcx: 'a> { - tcx: &'a TyCtxt<'tcx>, - var_origins: RefCell>, - - // Constraints of the form `A <= B` introduced by the region - // checker. Here at least one of `A` and `B` must be a region - // variable. - constraints: RefCell>>, - - // A "verify" is something that we need to verify after inference is - // done, but which does not directly affect inference in any way. - // - // An example is a `A <= B` where neither `A` nor `B` are - // inference variables. - verifys: RefCell>>, - - // A "given" is a relationship that is known to hold. In particular, - // we often know from closure fn signatures that a particular free - // region must be a subregion of a region variable: - // - // foo.iter().filter(<'a> |x: &'a &'b T| ...) - // - // In situations like this, `'b` is in fact a region variable - // introduced by the call to `iter()`, and `'a` is a bound region - // on the closure (as indicated by the `<'a>` prefix). If we are - // naive, we wind up inferring that `'b` must be `'static`, - // because we require that it be greater than `'a` and we do not - // know what `'a` is precisely. - // - // This hashmap is used to avoid that naive scenario. Basically we - // record the fact that `'a <= 'b` is implied by the fn signature, - // and then ignore the constraint when solving equations. This is - // a bit of a hack but seems to work. - givens: RefCell>, - - lubs: RefCell, - glbs: RefCell, - skolemization_count: Cell, - bound_count: Cell, - - // The undo log records actions that might later be undone. - // - // Note: when the undo_log is empty, we are not actively - // snapshotting. When the `start_snapshot()` method is called, we - // push an OpenSnapshot entry onto the list to indicate that we - // are now actively snapshotting. The reason for this is that - // otherwise we end up adding entries for things like the lower - // bound on a variable and so forth, which can never be rolled - // back. - undo_log: RefCell>, - unification_table: RefCell>, - - // This contains the results of inference. It begins as an empty - // option and only acquires a value after inference is complete. - values: RefCell>>, -} - -pub struct RegionSnapshot { - length: usize, - region_snapshot: unify::Snapshot, - skolemization_count: u32, -} - -impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { - pub fn new(tcx: &'a TyCtxt<'tcx>) -> RegionVarBindings<'a, 'tcx> { - RegionVarBindings { - tcx: tcx, - var_origins: RefCell::new(Vec::new()), - values: RefCell::new(None), - constraints: RefCell::new(FnvHashMap()), - verifys: RefCell::new(Vec::new()), - givens: RefCell::new(FnvHashSet()), - lubs: RefCell::new(FnvHashMap()), - glbs: RefCell::new(FnvHashMap()), - skolemization_count: Cell::new(0), - bound_count: Cell::new(0), - undo_log: RefCell::new(Vec::new()), - unification_table: RefCell::new(UnificationTable::new()), - } - } - - fn in_snapshot(&self) -> bool { - !self.undo_log.borrow().is_empty() - } - - pub fn start_snapshot(&self) -> RegionSnapshot { - let length = self.undo_log.borrow().len(); - debug!("RegionVarBindings: start_snapshot({})", length); - self.undo_log.borrow_mut().push(OpenSnapshot); - RegionSnapshot { - length: length, - region_snapshot: self.unification_table.borrow_mut().snapshot(), - skolemization_count: self.skolemization_count.get(), - } - } - - pub fn commit(&self, snapshot: RegionSnapshot) { - debug!("RegionVarBindings: commit({})", snapshot.length); - assert!(self.undo_log.borrow().len() > snapshot.length); - assert!((*self.undo_log.borrow())[snapshot.length] == OpenSnapshot); - - let mut undo_log = self.undo_log.borrow_mut(); - if snapshot.length == 0 { - undo_log.truncate(0); - } else { - (*undo_log)[snapshot.length] = CommitedSnapshot; - } - self.skolemization_count.set(snapshot.skolemization_count); - self.unification_table.borrow_mut().commit(snapshot.region_snapshot); - } - - pub fn rollback_to(&self, snapshot: RegionSnapshot) { - debug!("RegionVarBindings: rollback_to({:?})", snapshot); - let mut undo_log = self.undo_log.borrow_mut(); - assert!(undo_log.len() > snapshot.length); - assert!((*undo_log)[snapshot.length] == OpenSnapshot); - while undo_log.len() > snapshot.length + 1 { - match undo_log.pop().unwrap() { - OpenSnapshot => { - panic!("Failure to observe stack discipline"); - } - CommitedSnapshot => {} - AddVar(vid) => { - let mut var_origins = self.var_origins.borrow_mut(); - var_origins.pop().unwrap(); - assert_eq!(var_origins.len(), vid.index as usize); - } - AddConstraint(ref constraint) => { - self.constraints.borrow_mut().remove(constraint); - } - AddVerify(index) => { - self.verifys.borrow_mut().pop(); - assert_eq!(self.verifys.borrow().len(), index); - } - AddGiven(sub, sup) => { - self.givens.borrow_mut().remove(&(sub, sup)); - } - AddCombination(Glb, ref regions) => { - self.glbs.borrow_mut().remove(regions); - } - AddCombination(Lub, ref regions) => { - self.lubs.borrow_mut().remove(regions); - } - } - } - let c = undo_log.pop().unwrap(); - assert!(c == OpenSnapshot); - self.skolemization_count.set(snapshot.skolemization_count); - self.unification_table.borrow_mut() - .rollback_to(snapshot.region_snapshot); - } - - pub fn num_vars(&self) -> u32 { - let len = self.var_origins.borrow().len(); - // enforce no overflow - assert!(len as u32 as usize == len); - len as u32 - } - - pub fn new_region_var(&self, origin: RegionVariableOrigin) -> RegionVid { - let vid = RegionVid { index: self.num_vars() }; - self.var_origins.borrow_mut().push(origin.clone()); - - let u_vid = self.unification_table.borrow_mut().new_key( - unify_key::RegionVidKey { min_vid: vid } - ); - assert_eq!(vid, u_vid); - if self.in_snapshot() { - self.undo_log.borrow_mut().push(AddVar(vid)); - } - debug!("created new region variable {:?} with origin {:?}", - vid, - origin); - return vid; - } - - /// Creates a new skolemized region. Skolemized regions are fresh - /// regions used when performing higher-ranked computations. They - /// must be used in a very particular way and are never supposed - /// to "escape" out into error messages or the code at large. - /// - /// The idea is to always create a snapshot. Skolemized regions - /// can be created in the context of this snapshot, but once the - /// snapshot is committed or rolled back, their numbers will be - /// recycled, so you must be finished with them. See the extensive - /// comments in `higher_ranked.rs` to see how it works (in - /// particular, the subtyping comparison). - /// - /// The `snapshot` argument to this function is not really used; - /// it's just there to make it explicit which snapshot bounds the - /// skolemized region that results. - pub fn new_skolemized(&self, br: ty::BoundRegion, snapshot: &RegionSnapshot) -> Region { - assert!(self.in_snapshot()); - assert!(self.undo_log.borrow()[snapshot.length] == OpenSnapshot); - - let sc = self.skolemization_count.get(); - self.skolemization_count.set(sc + 1); - ReSkolemized(ty::SkolemizedRegionVid { index: sc }, br) - } - - pub fn new_bound(&self, debruijn: ty::DebruijnIndex) -> Region { - // Creates a fresh bound variable for use in GLB computations. - // See discussion of GLB computation in the large comment at - // the top of this file for more details. - // - // This computation is potentially wrong in the face of - // rollover. It's conceivable, if unlikely, that one might - // wind up with accidental capture for nested functions in - // that case, if the outer function had bound regions created - // a very long time before and the inner function somehow - // wound up rolling over such that supposedly fresh - // identifiers were in fact shadowed. For now, we just assert - // that there is no rollover -- eventually we should try to be - // robust against this possibility, either by checking the set - // of bound identifiers that appear in a given expression and - // ensure that we generate one that is distinct, or by - // changing the representation of bound regions in a fn - // declaration - - let sc = self.bound_count.get(); - self.bound_count.set(sc + 1); - - if sc >= self.bound_count.get() { - self.tcx.sess.bug("rollover in RegionInference new_bound()"); - } - - ReLateBound(debruijn, BrFresh(sc)) - } - - fn values_are_none(&self) -> bool { - self.values.borrow().is_none() - } - - fn add_constraint(&self, constraint: Constraint, origin: SubregionOrigin<'tcx>) { - // cannot add constraints once regions are resolved - assert!(self.values_are_none()); - - debug!("RegionVarBindings: add_constraint({:?})", constraint); - - if self.constraints.borrow_mut().insert(constraint, origin).is_none() { - if self.in_snapshot() { - self.undo_log.borrow_mut().push(AddConstraint(constraint)); - } - } - } - - fn add_verify(&self, verify: Verify<'tcx>) { - // cannot add verifys once regions are resolved - assert!(self.values_are_none()); - - debug!("RegionVarBindings: add_verify({:?})", verify); - - // skip no-op cases known to be satisfied - match verify { - VerifyGenericBound(_, _, _, VerifyBound::AllBounds(ref bs)) if bs.len() == 0 => { - return; - } - _ => {} - } - - let mut verifys = self.verifys.borrow_mut(); - let index = verifys.len(); - verifys.push(verify); - if self.in_snapshot() { - self.undo_log.borrow_mut().push(AddVerify(index)); - } - } - - pub fn add_given(&self, sub: ty::FreeRegion, sup: ty::RegionVid) { - // cannot add givens once regions are resolved - assert!(self.values_are_none()); - - let mut givens = self.givens.borrow_mut(); - if givens.insert((sub, sup)) { - debug!("add_given({:?} <= {:?})", sub, sup); - - self.undo_log.borrow_mut().push(AddGiven(sub, sup)); - } - } - - pub fn make_eqregion(&self, origin: SubregionOrigin<'tcx>, sub: Region, sup: Region) { - if sub != sup { - // Eventually, it would be nice to add direct support for - // equating regions. - self.make_subregion(origin.clone(), sub, sup); - self.make_subregion(origin, sup, sub); - - if let (ty::ReVar(sub), ty::ReVar(sup)) = (sub, sup) { - self.unification_table.borrow_mut().union(sub, sup); - } - } - } - - pub fn make_subregion(&self, origin: SubregionOrigin<'tcx>, sub: Region, sup: Region) { - // cannot add constraints once regions are resolved - assert!(self.values_are_none()); - - debug!("RegionVarBindings: make_subregion({:?}, {:?}) due to {:?}", - sub, - sup, - origin); - - match (sub, sup) { - (ReEarlyBound(..), _) | - (ReLateBound(..), _) | - (_, ReEarlyBound(..)) | - (_, ReLateBound(..)) => { - self.tcx.sess.span_bug(origin.span(), - &format!("cannot relate bound region: {:?} <= {:?}", - sub, - sup)); - } - (_, ReStatic) => { - // all regions are subregions of static, so we can ignore this - } - (ReVar(sub_id), ReVar(sup_id)) => { - self.add_constraint(ConstrainVarSubVar(sub_id, sup_id), origin); - } - (r, ReVar(sup_id)) => { - self.add_constraint(ConstrainRegSubVar(r, sup_id), origin); - } - (ReVar(sub_id), r) => { - self.add_constraint(ConstrainVarSubReg(sub_id, r), origin); - } - _ => { - self.add_verify(VerifyRegSubReg(origin, sub, sup)); - } - } - } - - /// See `Verify::VerifyGenericBound` - pub fn verify_generic_bound(&self, - origin: SubregionOrigin<'tcx>, - kind: GenericKind<'tcx>, - sub: Region, - bound: VerifyBound) { - self.add_verify(VerifyGenericBound(kind, origin, sub, bound)); - } - - pub fn lub_regions(&self, origin: SubregionOrigin<'tcx>, a: Region, b: Region) -> Region { - // cannot add constraints once regions are resolved - assert!(self.values_are_none()); - - debug!("RegionVarBindings: lub_regions({:?}, {:?})", a, b); - if a == ty::ReStatic || b == ty::ReStatic { - ReStatic // nothing lives longer than static - } else if a == b { - a // LUB(a,a) = a - } else { - self.combine_vars(Lub, a, b, origin.clone(), |this, old_r, new_r| { - this.make_subregion(origin.clone(), old_r, new_r) - }) - } - } - - pub fn glb_regions(&self, origin: SubregionOrigin<'tcx>, a: Region, b: Region) -> Region { - // cannot add constraints once regions are resolved - assert!(self.values_are_none()); - - debug!("RegionVarBindings: glb_regions({:?}, {:?})", a, b); - match (a, b) { - (ReStatic, r) | (r, ReStatic) => { - r // static lives longer than everything else - } - - _ if a == b => { - a // GLB(a,a) = a - } - - _ => { - self.combine_vars(Glb, a, b, origin.clone(), |this, old_r, new_r| { - this.make_subregion(origin.clone(), new_r, old_r) - }) - } - } - } - - pub fn resolve_var(&self, rid: RegionVid) -> ty::Region { - match *self.values.borrow() { - None => { - self.tcx.sess.span_bug((*self.var_origins.borrow())[rid.index as usize].span(), - "attempt to resolve region variable before values have \ - been computed!") - } - Some(ref values) => { - let r = lookup(values, rid); - debug!("resolve_var({:?}) = {:?}", rid, r); - r - } - } - } - - pub fn opportunistic_resolve_var(&self, rid: RegionVid) -> ty::Region { - ty::ReVar(self.unification_table.borrow_mut().find_value(rid).min_vid) - } - - fn combine_map(&self, t: CombineMapType) -> &RefCell { - match t { - Glb => &self.glbs, - Lub => &self.lubs, - } - } - - pub fn combine_vars(&self, - t: CombineMapType, - a: Region, - b: Region, - origin: SubregionOrigin<'tcx>, - mut relate: F) - -> Region - where F: FnMut(&RegionVarBindings<'a, 'tcx>, Region, Region) - { - let vars = TwoRegions { a: a, b: b }; - match self.combine_map(t).borrow().get(&vars) { - Some(&c) => { - return ReVar(c); - } - None => {} - } - let c = self.new_region_var(MiscVariable(origin.span())); - self.combine_map(t).borrow_mut().insert(vars, c); - if self.in_snapshot() { - self.undo_log.borrow_mut().push(AddCombination(t, vars)); - } - relate(self, a, ReVar(c)); - relate(self, b, ReVar(c)); - debug!("combine_vars() c={:?}", c); - ReVar(c) - } - - pub fn vars_created_since_snapshot(&self, mark: &RegionSnapshot) -> Vec { - self.undo_log.borrow()[mark.length..] - .iter() - .filter_map(|&elt| { - match elt { - AddVar(vid) => Some(vid), - _ => None, - } - }) - .collect() - } - - /// Computes all regions that have been related to `r0` in any way since the mark `mark` was - /// made---`r0` itself will be the first entry. This is used when checking whether skolemized - /// regions are being improperly related to other regions. - pub fn tainted(&self, mark: &RegionSnapshot, r0: Region) -> Vec { - debug!("tainted(mark={:?}, r0={:?})", mark, r0); - let _indenter = indenter(); - - // `result_set` acts as a worklist: we explore all outgoing - // edges and add any new regions we find to result_set. This - // is not a terribly efficient implementation. - let mut result_set = vec![r0]; - let mut result_index = 0; - while result_index < result_set.len() { - // nb: can't use usize::range() here because result_set grows - let r = result_set[result_index]; - debug!("result_index={}, r={:?}", result_index, r); - - for undo_entry in self.undo_log.borrow()[mark.length..].iter() { - match undo_entry { - &AddConstraint(ConstrainVarSubVar(a, b)) => { - consider_adding_bidirectional_edges(&mut result_set, r, ReVar(a), ReVar(b)); - } - &AddConstraint(ConstrainRegSubVar(a, b)) => { - consider_adding_bidirectional_edges(&mut result_set, r, a, ReVar(b)); - } - &AddConstraint(ConstrainVarSubReg(a, b)) => { - consider_adding_bidirectional_edges(&mut result_set, r, ReVar(a), b); - } - &AddGiven(a, b) => { - consider_adding_bidirectional_edges(&mut result_set, - r, - ReFree(a), - ReVar(b)); - } - &AddVerify(i) => { - match (*self.verifys.borrow())[i] { - VerifyRegSubReg(_, a, b) => { - consider_adding_bidirectional_edges(&mut result_set, r, a, b); - } - VerifyGenericBound(_, _, a, ref bound) => { - bound.for_each_region(&mut |b| { - consider_adding_bidirectional_edges(&mut result_set, r, a, b) - }); - } - } - } - &AddCombination(..) | - &AddVar(..) | - &OpenSnapshot | - &CommitedSnapshot => {} - } - } - - result_index += 1; - } - - return result_set; - - fn consider_adding_bidirectional_edges(result_set: &mut Vec, - r: Region, - r1: Region, - r2: Region) { - consider_adding_directed_edge(result_set, r, r1, r2); - consider_adding_directed_edge(result_set, r, r2, r1); - } - - fn consider_adding_directed_edge(result_set: &mut Vec, - r: Region, - r1: Region, - r2: Region) { - if r == r1 { - // Clearly, this is potentially inefficient. - if !result_set.iter().any(|x| *x == r2) { - result_set.push(r2); - } - } - } - } - - /// This function performs the actual region resolution. It must be - /// called after all constraints have been added. It performs a - /// fixed-point iteration to find region values which satisfy all - /// constraints, assuming such values can be found; if they cannot, - /// errors are reported. - pub fn resolve_regions(&self, - free_regions: &FreeRegionMap, - subject_node: ast::NodeId) - -> Vec> { - debug!("RegionVarBindings: resolve_regions()"); - let mut errors = vec![]; - let v = self.infer_variable_values(free_regions, &mut errors, subject_node); - *self.values.borrow_mut() = Some(v); - errors - } - - fn lub_concrete_regions(&self, free_regions: &FreeRegionMap, a: Region, b: Region) -> Region { - match (a, b) { - (ReLateBound(..), _) | - (_, ReLateBound(..)) | - (ReEarlyBound(..), _) | - (_, ReEarlyBound(..)) => { - self.tcx.sess.bug(&format!("cannot relate bound region: LUB({:?}, {:?})", a, b)); - } - - (ReStatic, _) | (_, ReStatic) => { - ReStatic // nothing lives longer than static - } - - (ReEmpty, r) | (r, ReEmpty) => { - r // everything lives longer than empty - } - - (ReVar(v_id), _) | (_, ReVar(v_id)) => { - self.tcx.sess.span_bug((*self.var_origins.borrow())[v_id.index as usize].span(), - &format!("lub_concrete_regions invoked with non-concrete \ - regions: {:?}, {:?}", - a, - b)); - } - - (ReFree(ref fr), ReScope(s_id)) | - (ReScope(s_id), ReFree(ref fr)) => { - let f = ReFree(*fr); - // A "free" region can be interpreted as "some region - // at least as big as the block fr.scope_id". So, we can - // reasonably compare free regions and scopes: - let r_id = self.tcx.region_maps.nearest_common_ancestor(fr.scope, s_id); - - if r_id == fr.scope { - // if the free region's scope `fr.scope_id` is bigger than - // the scope region `s_id`, then the LUB is the free - // region itself: - f - } else { - // otherwise, we don't know what the free region is, - // so we must conservatively say the LUB is static: - ReStatic - } - } - - (ReScope(a_id), ReScope(b_id)) => { - // The region corresponding to an outer block is a - // subtype of the region corresponding to an inner - // block. - ReScope(self.tcx.region_maps.nearest_common_ancestor(a_id, b_id)) - } - - (ReFree(a_fr), ReFree(b_fr)) => { - free_regions.lub_free_regions(a_fr, b_fr) - } - - // For these types, we cannot define any additional - // relationship: - (ReSkolemized(..), _) | - (_, ReSkolemized(..)) => { - if a == b { - a - } else { - ReStatic - } - } - } - } -} - -// ______________________________________________________________________ - -#[derive(Copy, Clone, Debug)] -pub enum VarValue { - Value(Region), - ErrorValue, -} - -struct VarData { - value: VarValue, -} - -struct RegionAndOrigin<'tcx> { - region: Region, - origin: SubregionOrigin<'tcx>, -} - -type RegionGraph = graph::Graph<(), Constraint>; - -impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { - fn infer_variable_values(&self, - free_regions: &FreeRegionMap, - errors: &mut Vec>, - subject: ast::NodeId) - -> Vec { - let mut var_data = self.construct_var_data(); - - // Dorky hack to cause `dump_constraints` to only get called - // if debug mode is enabled: - debug!("----() End constraint listing (subject={}) {:?}---", - subject, - self.dump_constraints(subject)); - graphviz::maybe_print_constraints_for(self, subject); - - let graph = self.construct_graph(); - self.expand_givens(&graph); - self.expansion(free_regions, &mut var_data); - self.contraction(free_regions, &mut var_data); - let values = self.extract_values_and_collect_conflicts(free_regions, - &var_data, - &graph, - errors); - self.collect_concrete_region_errors(free_regions, &values, errors); - values - } - - fn construct_var_data(&self) -> Vec { - (0..self.num_vars() as usize) - .map(|_| VarData { value: Value(ty::ReEmpty) }) - .collect() - } - - fn dump_constraints(&self, subject: ast::NodeId) { - debug!("----() Start constraint listing (subject={}) ()----", - subject); - for (idx, (constraint, _)) in self.constraints.borrow().iter().enumerate() { - debug!("Constraint {} => {:?}", idx, constraint); - } - } - - fn expand_givens(&self, graph: &RegionGraph) { - // Givens are a kind of horrible hack to account for - // constraints like 'c <= '0 that are known to hold due to - // closure signatures (see the comment above on the `givens` - // field). They should go away. But until they do, the role - // of this fn is to account for the transitive nature: - // - // Given 'c <= '0 - // and '0 <= '1 - // then 'c <= '1 - - let mut givens = self.givens.borrow_mut(); - let seeds: Vec<_> = givens.iter().cloned().collect(); - for (fr, vid) in seeds { - let seed_index = NodeIndex(vid.index as usize); - for succ_index in graph.depth_traverse(seed_index) { - let succ_index = succ_index.0 as u32; - if succ_index < self.num_vars() { - let succ_vid = RegionVid { index: succ_index }; - givens.insert((fr, succ_vid)); - } - } - } - } - - fn expansion(&self, free_regions: &FreeRegionMap, var_data: &mut [VarData]) { - self.iterate_until_fixed_point("Expansion", |constraint| { - debug!("expansion: constraint={:?} origin={:?}", - constraint, - self.constraints - .borrow() - .get(constraint) - .unwrap()); - match *constraint { - ConstrainRegSubVar(a_region, b_vid) => { - let b_data = &mut var_data[b_vid.index as usize]; - self.expand_node(free_regions, a_region, b_vid, b_data) - } - ConstrainVarSubVar(a_vid, b_vid) => { - match var_data[a_vid.index as usize].value { - ErrorValue => false, - Value(a_region) => { - let b_node = &mut var_data[b_vid.index as usize]; - self.expand_node(free_regions, a_region, b_vid, b_node) - } - } - } - ConstrainVarSubReg(..) => { - // This is a contraction constraint. Ignore it. - false - } - } - }) - } - - fn expand_node(&self, - free_regions: &FreeRegionMap, - a_region: Region, - b_vid: RegionVid, - b_data: &mut VarData) - -> bool { - debug!("expand_node({:?}, {:?} == {:?})", - a_region, - b_vid, - b_data.value); - - // Check if this relationship is implied by a given. - match a_region { - ty::ReFree(fr) => { - if self.givens.borrow().contains(&(fr, b_vid)) { - debug!("given"); - return false; - } - } - _ => {} - } - - match b_data.value { - Value(cur_region) => { - let lub = self.lub_concrete_regions(free_regions, a_region, cur_region); - if lub == cur_region { - return false; - } - - debug!("Expanding value of {:?} from {:?} to {:?}", - b_vid, - cur_region, - lub); - - b_data.value = Value(lub); - return true; - } - - ErrorValue => { - return false; - } - } - } - - // FIXME(#29436) -- this fn would just go away if we removed ConstrainVarSubReg - fn contraction(&self, free_regions: &FreeRegionMap, var_data: &mut [VarData]) { - self.iterate_until_fixed_point("Contraction", |constraint| { - debug!("contraction: constraint={:?} origin={:?}", - constraint, - self.constraints - .borrow() - .get(constraint) - .unwrap()); - match *constraint { - ConstrainRegSubVar(..) | - ConstrainVarSubVar(..) => { - // Expansion will ensure that these constraints hold. Ignore. - } - ConstrainVarSubReg(a_vid, b_region) => { - let a_data = &mut var_data[a_vid.index as usize]; - debug!("contraction: {:?} == {:?}, {:?}", - a_vid, - a_data.value, - b_region); - - let a_region = match a_data.value { - ErrorValue => return false, - Value(a_region) => a_region, - }; - - if !free_regions.is_subregion_of(self.tcx, a_region, b_region) { - debug!("Setting {:?} to ErrorValue: {:?} not subregion of {:?}", - a_vid, - a_region, - b_region); - a_data.value = ErrorValue; - } - } - } - - false - }) - } - - fn collect_concrete_region_errors(&self, - free_regions: &FreeRegionMap, - values: &Vec, - errors: &mut Vec>) { - let mut reg_reg_dups = FnvHashSet(); - for verify in self.verifys.borrow().iter() { - match *verify { - VerifyRegSubReg(ref origin, sub, sup) => { - if free_regions.is_subregion_of(self.tcx, sub, sup) { - continue; - } - - if !reg_reg_dups.insert((sub, sup)) { - continue; - } - - debug!("region inference error at {:?}: {:?} <= {:?} is not true", - origin, - sub, - sup); - - errors.push(ConcreteFailure((*origin).clone(), sub, sup)); - } - - VerifyGenericBound(ref kind, ref origin, sub, ref bound) => { - let sub = normalize(values, sub); - if bound.is_met(self.tcx, free_regions, values, sub) { - continue; - } - - debug!("region inference error at {:?}: verifying {:?} <= {:?}", - origin, - sub, - bound); - - errors.push(GenericBoundFailure((*origin).clone(), kind.clone(), sub)); - } - } - } - } - - fn extract_values_and_collect_conflicts(&self, - free_regions: &FreeRegionMap, - var_data: &[VarData], - graph: &RegionGraph, - errors: &mut Vec>) - -> Vec { - debug!("extract_values_and_collect_conflicts()"); - - // This is the best way that I have found to suppress - // duplicate and related errors. Basically we keep a set of - // flags for every node. Whenever an error occurs, we will - // walk some portion of the graph looking to find pairs of - // conflicting regions to report to the user. As we walk, we - // trip the flags from false to true, and if we find that - // we've already reported an error involving any particular - // node we just stop and don't report the current error. The - // idea is to report errors that derive from independent - // regions of the graph, but not those that derive from - // overlapping locations. - let mut dup_vec = vec![u32::MAX; self.num_vars() as usize]; - - for idx in 0..self.num_vars() as usize { - match var_data[idx].value { - Value(_) => { - /* Inference successful */ - } - ErrorValue => { - /* Inference impossible, this value contains - inconsistent constraints. - - I think that in this case we should report an - error now---unlike the case above, we can't - wait to see whether the user needs the result - of this variable. The reason is that the mere - existence of this variable implies that the - region graph is inconsistent, whether or not it - is used. - - For example, we may have created a region - variable that is the GLB of two other regions - which do not have a GLB. Even if that variable - is not used, it implies that those two regions - *should* have a GLB. - - At least I think this is true. It may be that - the mere existence of a conflict in a region variable - that is not used is not a problem, so if this rule - starts to create problems we'll have to revisit - this portion of the code and think hard about it. =) */ - - let node_vid = RegionVid { index: idx as u32 }; - self.collect_error_for_expanding_node(free_regions, - graph, - &mut dup_vec, - node_vid, - errors); - } - } - } - - (0..self.num_vars() as usize).map(|idx| var_data[idx].value).collect() - } - - fn construct_graph(&self) -> RegionGraph { - let num_vars = self.num_vars(); - - let constraints = self.constraints.borrow(); - - let mut graph = graph::Graph::new(); - - for _ in 0..num_vars { - graph.add_node(()); - } - - // Issue #30438: two distinct dummy nodes, one for incoming - // edges (dummy_source) and another for outgoing edges - // (dummy_sink). In `dummy -> a -> b -> dummy`, using one - // dummy node leads one to think (erroneously) there exists a - // path from `b` to `a`. Two dummy nodes sidesteps the issue. - let dummy_source = graph.add_node(()); - let dummy_sink = graph.add_node(()); - - for (constraint, _) in constraints.iter() { - match *constraint { - ConstrainVarSubVar(a_id, b_id) => { - graph.add_edge(NodeIndex(a_id.index as usize), - NodeIndex(b_id.index as usize), - *constraint); - } - ConstrainRegSubVar(_, b_id) => { - graph.add_edge(dummy_source, NodeIndex(b_id.index as usize), *constraint); - } - ConstrainVarSubReg(a_id, _) => { - graph.add_edge(NodeIndex(a_id.index as usize), dummy_sink, *constraint); - } - } - } - - return graph; - } - - fn collect_error_for_expanding_node(&self, - free_regions: &FreeRegionMap, - graph: &RegionGraph, - dup_vec: &mut [u32], - node_idx: RegionVid, - errors: &mut Vec>) { - // Errors in expanding nodes result from a lower-bound that is - // not contained by an upper-bound. - let (mut lower_bounds, lower_dup) = self.collect_concrete_regions(graph, - node_idx, - graph::INCOMING, - dup_vec); - let (mut upper_bounds, upper_dup) = self.collect_concrete_regions(graph, - node_idx, - graph::OUTGOING, - dup_vec); - - if lower_dup || upper_dup { - return; - } - - // We place free regions first because we are special casing - // SubSupConflict(ReFree, ReFree) when reporting error, and so - // the user will more likely get a specific suggestion. - fn free_regions_first(a: &RegionAndOrigin, b: &RegionAndOrigin) -> Ordering { - match (a.region, b.region) { - (ReFree(..), ReFree(..)) => Equal, - (ReFree(..), _) => Less, - (_, ReFree(..)) => Greater, - (_, _) => Equal, - } - } - lower_bounds.sort_by(|a, b| free_regions_first(a, b)); - upper_bounds.sort_by(|a, b| free_regions_first(a, b)); - - for lower_bound in &lower_bounds { - for upper_bound in &upper_bounds { - if !free_regions.is_subregion_of(self.tcx, lower_bound.region, upper_bound.region) { - let origin = (*self.var_origins.borrow())[node_idx.index as usize].clone(); - debug!("region inference error at {:?} for {:?}: SubSupConflict sub: {:?} \ - sup: {:?}", - origin, - node_idx, - lower_bound.region, - upper_bound.region); - errors.push(SubSupConflict(origin, - lower_bound.origin.clone(), - lower_bound.region, - upper_bound.origin.clone(), - upper_bound.region)); - return; - } - } - } - - self.tcx.sess.span_bug((*self.var_origins.borrow())[node_idx.index as usize].span(), - &format!("collect_error_for_expanding_node() could not find \ - error for var {:?}, lower_bounds={:?}, \ - upper_bounds={:?}", - node_idx, - lower_bounds, - upper_bounds)); - } - - fn collect_concrete_regions(&self, - graph: &RegionGraph, - orig_node_idx: RegionVid, - dir: Direction, - dup_vec: &mut [u32]) - -> (Vec>, bool) { - struct WalkState<'tcx> { - set: FnvHashSet, - stack: Vec, - result: Vec>, - dup_found: bool, - } - let mut state = WalkState { - set: FnvHashSet(), - stack: vec![orig_node_idx], - result: Vec::new(), - dup_found: false, - }; - state.set.insert(orig_node_idx); - - // to start off the process, walk the source node in the - // direction specified - process_edges(self, &mut state, graph, orig_node_idx, dir); - - while !state.stack.is_empty() { - let node_idx = state.stack.pop().unwrap(); - - // check whether we've visited this node on some previous walk - if dup_vec[node_idx.index as usize] == u32::MAX { - dup_vec[node_idx.index as usize] = orig_node_idx.index; - } else if dup_vec[node_idx.index as usize] != orig_node_idx.index { - state.dup_found = true; - } - - debug!("collect_concrete_regions(orig_node_idx={:?}, node_idx={:?})", - orig_node_idx, - node_idx); - - // figure out the direction from which this node takes its - // values, and search for concrete regions etc in that direction - let dir = graph::INCOMING; - process_edges(self, &mut state, graph, node_idx, dir); - } - - let WalkState {result, dup_found, ..} = state; - return (result, dup_found); - - fn process_edges<'a, 'tcx>(this: &RegionVarBindings<'a, 'tcx>, - state: &mut WalkState<'tcx>, - graph: &RegionGraph, - source_vid: RegionVid, - dir: Direction) { - debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir); - - let source_node_index = NodeIndex(source_vid.index as usize); - for (_, edge) in graph.adjacent_edges(source_node_index, dir) { - match edge.data { - ConstrainVarSubVar(from_vid, to_vid) => { - let opp_vid = if from_vid == source_vid { - to_vid - } else { - from_vid - }; - if state.set.insert(opp_vid) { - state.stack.push(opp_vid); - } - } - - ConstrainRegSubVar(region, _) | - ConstrainVarSubReg(_, region) => { - state.result.push(RegionAndOrigin { - region: region, - origin: this.constraints.borrow().get(&edge.data).unwrap().clone(), - }); - } - } - } - } - } - - fn iterate_until_fixed_point(&self, tag: &str, mut body: F) - where F: FnMut(&Constraint) -> bool - { - let mut iteration = 0; - let mut changed = true; - while changed { - changed = false; - iteration += 1; - debug!("---- {} Iteration {}{}", "#", tag, iteration); - for (constraint, _) in self.constraints.borrow().iter() { - let edge_changed = body(constraint); - if edge_changed { - debug!("Updated due to constraint {:?}", constraint); - changed = true; - } - } - } - debug!("---- {} Complete after {} iteration(s)", tag, iteration); - } - -} - -impl<'tcx> fmt::Debug for Verify<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - VerifyRegSubReg(_, ref a, ref b) => { - write!(f, "VerifyRegSubReg({:?}, {:?})", a, b) - } - VerifyGenericBound(_, ref p, ref a, ref bs) => { - write!(f, "VerifyGenericBound({:?}, {:?}, {:?})", p, a, bs) - } - } - } -} - -fn normalize(values: &Vec, r: ty::Region) -> ty::Region { - match r { - ty::ReVar(rid) => lookup(values, rid), - _ => r, - } -} - -fn lookup(values: &Vec, rid: ty::RegionVid) -> ty::Region { - match values[rid.index as usize] { - Value(r) => r, - ErrorValue => ReStatic, // Previously reported error. - } -} - -impl<'tcx> fmt::Debug for RegionAndOrigin<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "RegionAndOrigin({:?},{:?})", self.region, self.origin) - } -} - -impl fmt::Debug for RegionSnapshot { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "RegionSnapshot(length={},skolemization={})", - self.length, self.skolemization_count) - } -} - -impl<'tcx> fmt::Debug for GenericKind<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - GenericKind::Param(ref p) => write!(f, "{:?}", p), - GenericKind::Projection(ref p) => write!(f, "{:?}", p), - } - } -} - -impl<'tcx> fmt::Display for GenericKind<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - GenericKind::Param(ref p) => write!(f, "{}", p), - GenericKind::Projection(ref p) => write!(f, "{}", p), - } - } -} - -impl<'tcx> GenericKind<'tcx> { - pub fn to_ty(&self, tcx: &TyCtxt<'tcx>) -> Ty<'tcx> { - match *self { - GenericKind::Param(ref p) => p.to_ty(tcx), - GenericKind::Projection(ref p) => tcx.mk_projection(p.trait_ref.clone(), p.item_name), - } - } -} - -impl VerifyBound { - fn for_each_region(&self, f: &mut FnMut(ty::Region)) { - match self { - &VerifyBound::AnyRegion(ref rs) | - &VerifyBound::AllRegions(ref rs) => for &r in rs { - f(r); - }, - - &VerifyBound::AnyBound(ref bs) | - &VerifyBound::AllBounds(ref bs) => for b in bs { - b.for_each_region(f); - }, - } - } - - pub fn must_hold(&self) -> bool { - match self { - &VerifyBound::AnyRegion(ref bs) => bs.contains(&ty::ReStatic), - &VerifyBound::AllRegions(ref bs) => bs.is_empty(), - &VerifyBound::AnyBound(ref bs) => bs.iter().any(|b| b.must_hold()), - &VerifyBound::AllBounds(ref bs) => bs.iter().all(|b| b.must_hold()), - } - } - - pub fn cannot_hold(&self) -> bool { - match self { - &VerifyBound::AnyRegion(ref bs) => bs.is_empty(), - &VerifyBound::AllRegions(ref bs) => bs.contains(&ty::ReEmpty), - &VerifyBound::AnyBound(ref bs) => bs.iter().all(|b| b.cannot_hold()), - &VerifyBound::AllBounds(ref bs) => bs.iter().any(|b| b.cannot_hold()), - } - } - - pub fn or(self, vb: VerifyBound) -> VerifyBound { - if self.must_hold() || vb.cannot_hold() { - self - } else if self.cannot_hold() || vb.must_hold() { - vb - } else { - VerifyBound::AnyBound(vec![self, vb]) - } - } - - pub fn and(self, vb: VerifyBound) -> VerifyBound { - if self.must_hold() && vb.must_hold() { - self - } else if self.cannot_hold() && vb.cannot_hold() { - self - } else { - VerifyBound::AllBounds(vec![self, vb]) - } - } - - fn is_met<'tcx>(&self, - tcx: &TyCtxt<'tcx>, - free_regions: &FreeRegionMap, - var_values: &Vec, - min: ty::Region) - -> bool { - match self { - &VerifyBound::AnyRegion(ref rs) => - rs.iter() - .map(|&r| normalize(var_values, r)) - .any(|r| free_regions.is_subregion_of(tcx, min, r)), - - &VerifyBound::AllRegions(ref rs) => - rs.iter() - .map(|&r| normalize(var_values, r)) - .all(|r| free_regions.is_subregion_of(tcx, min, r)), - - &VerifyBound::AnyBound(ref bs) => - bs.iter() - .any(|b| b.is_met(tcx, free_regions, var_values, min)), - - &VerifyBound::AllBounds(ref bs) => - bs.iter() - .all(|b| b.is_met(tcx, free_regions, var_values, min)), - } - } -} diff --git a/src/librustc/middle/infer/resolve.rs b/src/librustc/middle/infer/resolve.rs deleted file mode 100644 index 8c610589844..00000000000 --- a/src/librustc/middle/infer/resolve.rs +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::{InferCtxt, FixupError, FixupResult}; -use middle::ty::{self, Ty, TyCtxt, TypeFoldable}; - -/////////////////////////////////////////////////////////////////////////// -// OPPORTUNISTIC TYPE RESOLVER - -/// The opportunistic type resolver can be used at any time. It simply replaces -/// type variables that have been unified with the things they have -/// been unified with (similar to `shallow_resolve`, but deep). This is -/// useful for printing messages etc but also required at various -/// points for correctness. -pub struct OpportunisticTypeResolver<'a, 'tcx:'a> { - infcx: &'a InferCtxt<'a, 'tcx>, -} - -impl<'a, 'tcx> OpportunisticTypeResolver<'a, 'tcx> { - pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> OpportunisticTypeResolver<'a, 'tcx> { - OpportunisticTypeResolver { infcx: infcx } - } -} - -impl<'a, 'tcx> ty::fold::TypeFolder<'tcx> for OpportunisticTypeResolver<'a, 'tcx> { - fn tcx(&self) -> &TyCtxt<'tcx> { - self.infcx.tcx - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.has_infer_types() { - t // micro-optimize -- if there is nothing in this type that this fold affects... - } else { - let t0 = self.infcx.shallow_resolve(t); - t0.super_fold_with(self) - } - } -} - -/// The opportunistic type and region resolver is similar to the -/// opportunistic type resolver, but also opportunistly resolves -/// regions. It is useful for canonicalization. -pub struct OpportunisticTypeAndRegionResolver<'a, 'tcx:'a> { - infcx: &'a InferCtxt<'a, 'tcx>, -} - -impl<'a, 'tcx> OpportunisticTypeAndRegionResolver<'a, 'tcx> { - pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self { - OpportunisticTypeAndRegionResolver { infcx: infcx } - } -} - -impl<'a, 'tcx> ty::fold::TypeFolder<'tcx> for OpportunisticTypeAndRegionResolver<'a, 'tcx> { - fn tcx(&self) -> &TyCtxt<'tcx> { - self.infcx.tcx - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.needs_infer() { - t // micro-optimize -- if there is nothing in this type that this fold affects... - } else { - let t0 = self.infcx.shallow_resolve(t); - t0.super_fold_with(self) - } - } - - fn fold_region(&mut self, r: ty::Region) -> ty::Region { - match r { - ty::ReVar(rid) => self.infcx.region_vars.opportunistic_resolve_var(rid), - _ => r, - } - } -} - -/////////////////////////////////////////////////////////////////////////// -// FULL TYPE RESOLUTION - -/// Full type resolution replaces all type and region variables with -/// their concrete results. If any variable cannot be replaced (never unified, etc) -/// then an `Err` result is returned. -pub fn fully_resolve<'a, 'tcx, T>(infcx: &InferCtxt<'a,'tcx>, value: &T) -> FixupResult - where T : TypeFoldable<'tcx> -{ - let mut full_resolver = FullTypeResolver { infcx: infcx, err: None }; - let result = value.fold_with(&mut full_resolver); - match full_resolver.err { - None => Ok(result), - Some(e) => Err(e), - } -} - -// N.B. This type is not public because the protocol around checking the -// `err` field is not enforcable otherwise. -struct FullTypeResolver<'a, 'tcx:'a> { - infcx: &'a InferCtxt<'a, 'tcx>, - err: Option, -} - -impl<'a, 'tcx> ty::fold::TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { - fn tcx(&self) -> &TyCtxt<'tcx> { - self.infcx.tcx - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.needs_infer() { - t // micro-optimize -- if there is nothing in this type that this fold affects... - } else { - let t = self.infcx.shallow_resolve(t); - match t.sty { - ty::TyInfer(ty::TyVar(vid)) => { - self.err = Some(FixupError::UnresolvedTy(vid)); - self.tcx().types.err - } - ty::TyInfer(ty::IntVar(vid)) => { - self.err = Some(FixupError::UnresolvedIntTy(vid)); - self.tcx().types.err - } - ty::TyInfer(ty::FloatVar(vid)) => { - self.err = Some(FixupError::UnresolvedFloatTy(vid)); - self.tcx().types.err - } - ty::TyInfer(_) => { - self.infcx.tcx.sess.bug( - &format!("Unexpected type in full type resolver: {:?}", - t)); - } - _ => { - t.super_fold_with(self) - } - } - } - } - - fn fold_region(&mut self, r: ty::Region) -> ty::Region { - match r { - ty::ReVar(rid) => self.infcx.region_vars.resolve_var(rid), - _ => r, - } - } -} diff --git a/src/librustc/middle/infer/sub.rs b/src/librustc/middle/infer/sub.rs deleted file mode 100644 index e94311697c3..00000000000 --- a/src/librustc/middle/infer/sub.rs +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::combine::{self, CombineFields}; -use super::higher_ranked::HigherRankedRelations; -use super::SubregionOrigin; -use super::type_variable::{SubtypeOf, SupertypeOf}; - -use middle::ty::{self, Ty, TyCtxt}; -use middle::ty::TyVar; -use middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation}; -use std::mem; - -/// Ensures `a` is made a subtype of `b`. Returns `a` on success. -pub struct Sub<'a, 'tcx: 'a> { - fields: CombineFields<'a, 'tcx>, -} - -impl<'a, 'tcx> Sub<'a, 'tcx> { - pub fn new(f: CombineFields<'a, 'tcx>) -> Sub<'a, 'tcx> { - Sub { fields: f } - } -} - -impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Sub<'a, 'tcx> { - fn tag(&self) -> &'static str { "Sub" } - fn tcx(&self) -> &'a TyCtxt<'tcx> { self.fields.infcx.tcx } - fn a_is_expected(&self) -> bool { self.fields.a_is_expected } - - fn with_cause(&mut self, cause: Cause, f: F) -> R - where F: FnOnce(&mut Self) -> R - { - debug!("sub with_cause={:?}", cause); - let old_cause = mem::replace(&mut self.fields.cause, Some(cause)); - let r = f(self); - debug!("sub old_cause={:?}", old_cause); - self.fields.cause = old_cause; - r - } - - fn relate_with_variance>(&mut self, - variance: ty::Variance, - a: &T, - b: &T) - -> RelateResult<'tcx, T> - { - match variance { - ty::Invariant => self.fields.equate().relate(a, b), - ty::Covariant => self.relate(a, b), - ty::Bivariant => self.fields.bivariate().relate(a, b), - ty::Contravariant => self.fields.switch_expected().sub().relate(b, a), - } - } - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - debug!("{}.tys({:?}, {:?})", self.tag(), a, b); - - if a == b { return Ok(a); } - - let infcx = self.fields.infcx; - let a = infcx.type_variables.borrow_mut().replace_if_possible(a); - let b = infcx.type_variables.borrow_mut().replace_if_possible(b); - match (&a.sty, &b.sty) { - (&ty::TyInfer(TyVar(a_id)), &ty::TyInfer(TyVar(b_id))) => { - infcx.type_variables - .borrow_mut() - .relate_vars(a_id, SubtypeOf, b_id); - Ok(a) - } - (&ty::TyInfer(TyVar(a_id)), _) => { - self.fields - .switch_expected() - .instantiate(b, SupertypeOf, a_id)?; - Ok(a) - } - (_, &ty::TyInfer(TyVar(b_id))) => { - self.fields.instantiate(a, SubtypeOf, b_id)?; - Ok(a) - } - - (&ty::TyError, _) | (_, &ty::TyError) => { - Ok(self.tcx().types.err) - } - - _ => { - combine::super_combine_tys(self.fields.infcx, self, a, b)?; - Ok(a) - } - } - } - - fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> { - debug!("{}.regions({:?}, {:?}) self.cause={:?}", - self.tag(), a, b, self.fields.cause); - // FIXME -- we have more fine-grained information available - // from the "cause" field, we could perhaps give more tailored - // error messages. - let origin = SubregionOrigin::Subtype(self.fields.trace.clone()); - self.fields.infcx.region_vars.make_subregion(origin, a, b); - Ok(a) - } - - fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) - -> RelateResult<'tcx, ty::Binder> - where T: Relate<'a,'tcx> - { - self.fields.higher_ranked_sub(a, b) - } -} diff --git a/src/librustc/middle/infer/type_variable.rs b/src/librustc/middle/infer/type_variable.rs deleted file mode 100644 index fe66ea5a1ea..00000000000 --- a/src/librustc/middle/infer/type_variable.rs +++ /dev/null @@ -1,324 +0,0 @@ -// Copyright 2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub use self::RelationDir::*; -use self::TypeVariableValue::*; -use self::UndoEntry::*; -use middle::def_id::{DefId}; -use middle::ty::{self, Ty}; -use syntax::codemap::Span; - -use std::cmp::min; -use std::marker::PhantomData; -use std::mem; -use std::u32; -use rustc_data_structures::snapshot_vec as sv; -use rustc_data_structures::unify as ut; - -pub struct TypeVariableTable<'tcx> { - values: sv::SnapshotVec>, - eq_relations: ut::UnificationTable, -} - -struct TypeVariableData<'tcx> { - value: TypeVariableValue<'tcx>, - diverging: bool -} - -enum TypeVariableValue<'tcx> { - Known(Ty<'tcx>), - Bounded { - relations: Vec, - default: Option> - } -} - -// We will use this to store the required information to recapitulate what happened when -// an error occurs. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct Default<'tcx> { - pub ty: Ty<'tcx>, - /// The span where the default was incurred - pub origin_span: Span, - /// The definition that the default originates from - pub def_id: DefId -} - -pub struct Snapshot { - snapshot: sv::Snapshot, - eq_snapshot: ut::Snapshot, -} - -enum UndoEntry<'tcx> { - // The type of the var was specified. - SpecifyVar(ty::TyVid, Vec, Option>), - Relate(ty::TyVid, ty::TyVid), - RelateRange(ty::TyVid, usize), -} - -struct Delegate<'tcx>(PhantomData<&'tcx ()>); - -type Relation = (RelationDir, ty::TyVid); - -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub enum RelationDir { - SubtypeOf, SupertypeOf, EqTo, BiTo -} - -impl RelationDir { - fn opposite(self) -> RelationDir { - match self { - SubtypeOf => SupertypeOf, - SupertypeOf => SubtypeOf, - EqTo => EqTo, - BiTo => BiTo, - } - } -} - -impl<'tcx> TypeVariableTable<'tcx> { - pub fn new() -> TypeVariableTable<'tcx> { - TypeVariableTable { - values: sv::SnapshotVec::new(), - eq_relations: ut::UnificationTable::new(), - } - } - - fn relations<'a>(&'a mut self, a: ty::TyVid) -> &'a mut Vec { - relations(self.values.get_mut(a.index as usize)) - } - - pub fn default(&self, vid: ty::TyVid) -> Option> { - match &self.values.get(vid.index as usize).value { - &Known(_) => None, - &Bounded { ref default, .. } => default.clone() - } - } - - pub fn var_diverges<'a>(&'a self, vid: ty::TyVid) -> bool { - self.values.get(vid.index as usize).diverging - } - - /// Records that `a <: b`, `a :> b`, or `a == b`, depending on `dir`. - /// - /// Precondition: neither `a` nor `b` are known. - pub fn relate_vars(&mut self, a: ty::TyVid, dir: RelationDir, b: ty::TyVid) { - let a = self.root_var(a); - let b = self.root_var(b); - if a != b { - if dir == EqTo { - // a and b must be equal which we mark in the unification table - let root = self.eq_relations.union(a, b); - // In addition to being equal, all relations from the variable which is no longer - // the root must be added to the root so they are not forgotten as the other - // variable should no longer be referenced (other than to get the root) - let other = if a == root { b } else { a }; - let count = { - let (relations, root_relations) = if other.index < root.index { - let (pre, post) = self.values.split_at_mut(root.index as usize); - (relations(&mut pre[other.index as usize]), relations(&mut post[0])) - } else { - let (pre, post) = self.values.split_at_mut(other.index as usize); - (relations(&mut post[0]), relations(&mut pre[root.index as usize])) - }; - root_relations.extend_from_slice(relations); - relations.len() - }; - self.values.record(RelateRange(root, count)); - } else { - self.relations(a).push((dir, b)); - self.relations(b).push((dir.opposite(), a)); - self.values.record(Relate(a, b)); - } - } - } - - /// Instantiates `vid` with the type `ty` and then pushes an entry onto `stack` for each of the - /// relations of `vid` to other variables. The relations will have the form `(ty, dir, vid1)` - /// where `vid1` is some other variable id. - /// - /// Precondition: `vid` must be a root in the unification table - pub fn instantiate_and_push( - &mut self, - vid: ty::TyVid, - ty: Ty<'tcx>, - stack: &mut Vec<(Ty<'tcx>, RelationDir, ty::TyVid)>) - { - debug_assert!(self.root_var(vid) == vid); - let old_value = { - let value_ptr = &mut self.values.get_mut(vid.index as usize).value; - mem::replace(value_ptr, Known(ty)) - }; - - let (relations, default) = match old_value { - Bounded { relations, default } => (relations, default), - Known(_) => panic!("Asked to instantiate variable that is \ - already instantiated") - }; - - for &(dir, vid) in &relations { - stack.push((ty, dir, vid)); - } - - self.values.record(SpecifyVar(vid, relations, default)); - } - - pub fn new_var(&mut self, - diverging: bool, - default: Option>) -> ty::TyVid { - self.eq_relations.new_key(()); - let index = self.values.push(TypeVariableData { - value: Bounded { relations: vec![], default: default }, - diverging: diverging - }); - ty::TyVid { index: index as u32 } - } - - pub fn root_var(&mut self, vid: ty::TyVid) -> ty::TyVid { - self.eq_relations.find(vid) - } - - pub fn probe(&mut self, vid: ty::TyVid) -> Option> { - let vid = self.root_var(vid); - self.probe_root(vid) - } - - /// Retrieves the type of `vid` given that it is currently a root in the unification table - pub fn probe_root(&mut self, vid: ty::TyVid) -> Option> { - debug_assert!(self.root_var(vid) == vid); - match self.values.get(vid.index as usize).value { - Bounded { .. } => None, - Known(t) => Some(t) - } - } - - pub fn replace_if_possible(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match t.sty { - ty::TyInfer(ty::TyVar(v)) => { - match self.probe(v) { - None => t, - Some(u) => u - } - } - _ => t, - } - } - - pub fn snapshot(&mut self) -> Snapshot { - Snapshot { - snapshot: self.values.start_snapshot(), - eq_snapshot: self.eq_relations.snapshot(), - } - } - - pub fn rollback_to(&mut self, s: Snapshot) { - self.values.rollback_to(s.snapshot); - self.eq_relations.rollback_to(s.eq_snapshot); - } - - pub fn commit(&mut self, s: Snapshot) { - self.values.commit(s.snapshot); - self.eq_relations.commit(s.eq_snapshot); - } - - pub fn types_escaping_snapshot(&mut self, s: &Snapshot) -> Vec> { - /*! - * Find the set of type variables that existed *before* `s` - * but which have only been unified since `s` started, and - * return the types with which they were unified. So if we had - * a type variable `V0`, then we started the snapshot, then we - * created a type variable `V1`, unifed `V0` with `T0`, and - * unified `V1` with `T1`, this function would return `{T0}`. - */ - - let mut new_elem_threshold = u32::MAX; - let mut escaping_types = Vec::new(); - let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot); - debug!("actions_since_snapshot.len() = {}", actions_since_snapshot.len()); - for action in actions_since_snapshot { - match *action { - sv::UndoLog::NewElem(index) => { - // if any new variables were created during the - // snapshot, remember the lower index (which will - // always be the first one we see). Note that this - // action must precede those variables being - // specified. - new_elem_threshold = min(new_elem_threshold, index as u32); - debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold); - } - - sv::UndoLog::Other(SpecifyVar(vid, _, _)) => { - if vid.index < new_elem_threshold { - // quick check to see if this variable was - // created since the snapshot started or not. - let escaping_type = match self.values.get(vid.index as usize).value { - Bounded { .. } => unreachable!(), - Known(ty) => ty, - }; - escaping_types.push(escaping_type); - } - debug!("SpecifyVar({:?}) new_elem_threshold={}", vid, new_elem_threshold); - } - - _ => { } - } - } - - escaping_types - } - - pub fn unsolved_variables(&mut self) -> Vec { - (0..self.values.len()) - .filter_map(|i| { - let vid = ty::TyVid { index: i as u32 }; - if self.probe(vid).is_some() { - None - } else { - Some(vid) - } - }) - .collect() - } -} - -impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> { - type Value = TypeVariableData<'tcx>; - type Undo = UndoEntry<'tcx>; - - fn reverse(values: &mut Vec>, action: UndoEntry<'tcx>) { - match action { - SpecifyVar(vid, relations, default) => { - values[vid.index as usize].value = Bounded { - relations: relations, - default: default - }; - } - - Relate(a, b) => { - relations(&mut (*values)[a.index as usize]).pop(); - relations(&mut (*values)[b.index as usize]).pop(); - } - - RelateRange(i, n) => { - let relations = relations(&mut (*values)[i.index as usize]); - for _ in 0..n { - relations.pop(); - } - } - } - } -} - -fn relations<'a>(v: &'a mut TypeVariableData) -> &'a mut Vec { - match v.value { - Known(_) => panic!("var_sub_var: variable is known"), - Bounded { ref mut relations, .. } => relations - } -} diff --git a/src/librustc/middle/infer/unify_key.rs b/src/librustc/middle/infer/unify_key.rs deleted file mode 100644 index 3f8c3fbce04..00000000000 --- a/src/librustc/middle/infer/unify_key.rs +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2012-2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use syntax::ast; -use middle::ty::{self, IntVarValue, Ty, TyCtxt}; -use rustc_data_structures::unify::{Combine, UnifyKey}; - -pub trait ToType<'tcx> { - fn to_type(&self, tcx: &TyCtxt<'tcx>) -> Ty<'tcx>; -} - -impl UnifyKey for ty::IntVid { - type Value = Option; - fn index(&self) -> u32 { self.index } - fn from_index(i: u32) -> ty::IntVid { ty::IntVid { index: i } } - fn tag(_: Option) -> &'static str { "IntVid" } -} - -#[derive(PartialEq, Copy, Clone, Debug)] -pub struct RegionVidKey { - /// The minimum region vid in the unification set. This is needed - /// to have a canonical name for a type to prevent infinite - /// recursion. - pub min_vid: ty::RegionVid -} - -impl Combine for RegionVidKey { - fn combine(&self, other: &RegionVidKey) -> RegionVidKey { - let min_vid = if self.min_vid.index < other.min_vid.index { - self.min_vid - } else { - other.min_vid - }; - - RegionVidKey { min_vid: min_vid } - } -} - -impl UnifyKey for ty::RegionVid { - type Value = RegionVidKey; - fn index(&self) -> u32 { self.index } - fn from_index(i: u32) -> ty::RegionVid { ty::RegionVid { index: i } } - fn tag(_: Option) -> &'static str { "RegionVid" } -} - -impl<'tcx> ToType<'tcx> for IntVarValue { - fn to_type(&self, tcx: &TyCtxt<'tcx>) -> Ty<'tcx> { - match *self { - ty::IntType(i) => tcx.mk_mach_int(i), - ty::UintType(i) => tcx.mk_mach_uint(i), - } - } -} - -// Floating point type keys - -impl UnifyKey for ty::FloatVid { - type Value = Option; - fn index(&self) -> u32 { self.index } - fn from_index(i: u32) -> ty::FloatVid { ty::FloatVid { index: i } } - fn tag(_: Option) -> &'static str { "FloatVid" } -} - -impl<'tcx> ToType<'tcx> for ast::FloatTy { - fn to_type(&self, tcx: &TyCtxt<'tcx>) -> Ty<'tcx> { - tcx.mk_mach_float(*self) - } -} - -impl UnifyKey for ty::TyVid { - type Value = (); - fn index(&self) -> u32 { self.index } - fn from_index(i: u32) -> ty::TyVid { ty::TyVid { index: i } } - fn tag(_: Option) -> &'static str { "TyVid" } -} diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index e3da34acb4b..939ea91cdd4 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -11,9 +11,9 @@ use dep_graph::DepNode; use middle::def::Def; use middle::def_id::DefId; -use middle::ty::subst::{Subst, Substs, EnumeratedItems}; -use middle::ty::{TransmuteRestriction, TyCtxt}; -use middle::ty::{self, Ty, TypeFoldable}; +use ty::subst::{Subst, Substs, EnumeratedItems}; +use ty::{TransmuteRestriction, TyCtxt}; +use ty::{self, Ty, TypeFoldable}; use std::fmt; diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index b08c2d6054c..bb0b8ed91df 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -26,7 +26,7 @@ use front::map as hir_map; use session::Session; use middle::cstore::CrateStore; use middle::def_id::DefId; -use middle::ty; +use ty; use middle::weak_lang_items; use util::nodemap::FnvHashMap; diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index ee39a4fc7df..f6eedb49e24 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -112,10 +112,10 @@ use self::VarKind::*; use dep_graph::DepNode; use middle::def::*; use middle::pat_util; -use middle::ty::{self, TyCtxt, ParameterEnvironment}; -use middle::traits::{self, ProjectionMode}; -use middle::infer; -use middle::ty::subst::Subst; +use ty::{self, TyCtxt, ParameterEnvironment}; +use traits::{self, ProjectionMode}; +use infer; +use ty::subst::Subst; use lint; use util::nodemap::NodeMap; diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index d2bc80a2cb2..6328f920cb7 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -73,11 +73,11 @@ use self::Aliasability::*; use middle::def_id::DefId; use front::map as ast_map; -use middle::infer; +use infer; use middle::const_qualif::ConstQualif; use middle::def::Def; -use middle::ty::adjustment; -use middle::ty::{self, Ty, TyCtxt}; +use ty::adjustment; +use ty::{self, Ty, TyCtxt}; use rustc_front::hir::{MutImmutable, MutMutable, PatKind}; use rustc_front::hir; diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs index 81166945115..b2b1344c4bb 100644 --- a/src/librustc/middle/pat_util.rs +++ b/src/librustc/middle/pat_util.rs @@ -10,7 +10,7 @@ use middle::def::*; use middle::def_id::DefId; -use middle::ty::TyCtxt; +use ty::TyCtxt; use util::nodemap::FnvHashMap; use syntax::ast; diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 601f069513d..2e01a7fc249 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -19,7 +19,7 @@ use dep_graph::DepNode; use front::map as ast_map; use middle::def::Def; use middle::def_id::DefId; -use middle::ty::{self, TyCtxt}; +use ty::{self, TyCtxt}; use middle::privacy; use session::config; use util::nodemap::NodeSet; diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index eb375205dee..1d1d05ea79f 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -21,7 +21,7 @@ use front::map as ast_map; use session::Session; use util::nodemap::{FnvHashMap, NodeMap, NodeSet}; use middle::cstore::InlinedItem; -use middle::ty; +use ty; use std::cell::RefCell; use std::collections::hash_map::Entry; @@ -280,7 +280,7 @@ pub struct RegionMaps { /// hierarchy based on their lexical mapping. This is used to /// handle the relationships between regions in a fn and in a /// closure defined by that fn. See the "Modeling closures" - /// section of the README in middle::infer::region_inference for + /// section of the README in infer::region_inference for /// more details. fn_tree: RefCell>, } @@ -291,7 +291,7 @@ pub struct Context { /// of the innermost fn body. Each fn forms its own disjoint tree /// in the region hierarchy. These fn bodies are themselves /// arranged into a tree. See the "Modeling closures" section of - /// the README in middle::infer::region_inference for more + /// the README in infer::region_inference for more /// details. root_id: Option, @@ -460,7 +460,7 @@ impl RegionMaps { self.scope_map.borrow()[id.0 as usize].into_option() } - #[allow(dead_code)] // used in middle::cfg + #[allow(dead_code)] // used in cfg pub fn encl_scope(&self, id: CodeExtent) -> CodeExtent { //! Returns the narrowest scope that encloses `id`, if any. self.opt_encl_scope(id).unwrap() @@ -587,7 +587,7 @@ impl RegionMaps { // different functions. Compare those fn for lexical // nesting. The reasoning behind this is subtle. See the // "Modeling closures" section of the README in - // middle::infer::region_inference for more details. + // infer::region_inference for more details. let a_root_scope = self.code_extent_data(a_ancestors[a_index]); let b_root_scope = self.code_extent_data(a_ancestors[a_index]); return match (a_root_scope, b_root_scope) { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 8d3a80854b4..6342599bf73 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -23,8 +23,8 @@ use front::map::Map; use session::Session; use middle::def::{Def, DefMap}; use middle::region; -use middle::ty::subst; -use middle::ty; +use ty::subst; +use ty; use std::fmt; use std::mem::replace; use syntax::ast; diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 2d92742ed0f..3a2f995a318 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -20,7 +20,7 @@ use lint; use middle::cstore::{CrateStore, LOCAL_CRATE}; use middle::def::Def; use middle::def_id::{CRATE_DEF_INDEX, DefId}; -use middle::ty::{self, TyCtxt}; +use ty::{self, TyCtxt}; use middle::privacy::AccessLevels; use syntax::parse::token::InternedString; use syntax::codemap::{Span, DUMMY_SP}; diff --git a/src/librustc/middle/traits/README.md b/src/librustc/middle/traits/README.md deleted file mode 100644 index ff72f9dd07e..00000000000 --- a/src/librustc/middle/traits/README.md +++ /dev/null @@ -1,470 +0,0 @@ -# TRAIT RESOLUTION - -This document describes the general process and points out some non-obvious -things. - -## Major concepts - -Trait resolution is the process of pairing up an impl with each -reference to a trait. So, for example, if there is a generic function like: - - fn clone_slice(x: &[T]) -> Vec { ... } - -and then a call to that function: - - let v: Vec = clone_slice([1, 2, 3]) - -it is the job of trait resolution to figure out (in which case) -whether there exists an impl of `isize : Clone` - -Note that in some cases, like generic functions, we may not be able to -find a specific impl, but we can figure out that the caller must -provide an impl. To see what I mean, consider the body of `clone_slice`: - - fn clone_slice(x: &[T]) -> Vec { - let mut v = Vec::new(); - for e in &x { - v.push((*e).clone()); // (*) - } - } - -The line marked `(*)` is only legal if `T` (the type of `*e`) -implements the `Clone` trait. Naturally, since we don't know what `T` -is, we can't find the specific impl; but based on the bound `T:Clone`, -we can say that there exists an impl which the caller must provide. - -We use the term *obligation* to refer to a trait reference in need of -an impl. - -## Overview - -Trait resolution consists of three major parts: - -- SELECTION: Deciding how to resolve a specific obligation. For - example, selection might decide that a specific obligation can be - resolved by employing an impl which matches the self type, or by - using a parameter bound. In the case of an impl, Selecting one - obligation can create *nested obligations* because of where clauses - on the impl itself. It may also require evaluating those nested - obligations to resolve ambiguities. - -- FULFILLMENT: The fulfillment code is what tracks that obligations - are completely fulfilled. Basically it is a worklist of obligations - to be selected: once selection is successful, the obligation is - removed from the worklist and any nested obligations are enqueued. - -- COHERENCE: The coherence checks are intended to ensure that there - are never overlapping impls, where two impls could be used with - equal precedence. - -## Selection - -Selection is the process of deciding whether an obligation can be -resolved and, if so, how it is to be resolved (via impl, where clause, etc). -The main interface is the `select()` function, which takes an obligation -and returns a `SelectionResult`. There are three possible outcomes: - -- `Ok(Some(selection))` -- yes, the obligation can be resolved, and - `selection` indicates how. If the impl was resolved via an impl, - then `selection` may also indicate nested obligations that are required - by the impl. - -- `Ok(None)` -- we are not yet sure whether the obligation can be - resolved or not. This happens most commonly when the obligation - contains unbound type variables. - -- `Err(err)` -- the obligation definitely cannot be resolved due to a - type error, or because there are no impls that could possibly apply, - etc. - -The basic algorithm for selection is broken into two big phases: -candidate assembly and confirmation. - -### Candidate assembly - -Searches for impls/where-clauses/etc that might -possibly be used to satisfy the obligation. Each of those is called -a candidate. To avoid ambiguity, we want to find exactly one -candidate that is definitively applicable. In some cases, we may not -know whether an impl/where-clause applies or not -- this occurs when -the obligation contains unbound inference variables. - -The basic idea for candidate assembly is to do a first pass in which -we identify all possible candidates. During this pass, all that we do -is try and unify the type parameters. (In particular, we ignore any -nested where clauses.) Presuming that this unification succeeds, the -impl is added as a candidate. - -Once this first pass is done, we can examine the set of candidates. If -it is a singleton set, then we are done: this is the only impl in -scope that could possibly apply. Otherwise, we can winnow down the set -of candidates by using where clauses and other conditions. If this -reduced set yields a single, unambiguous entry, we're good to go, -otherwise the result is considered ambiguous. - -#### The basic process: Inferring based on the impls we see - -This process is easier if we work through some examples. Consider -the following trait: - -``` -trait Convert { - fn convert(&self) -> Target; -} -``` - -This trait just has one method. It's about as simple as it gets. It -converts from the (implicit) `Self` type to the `Target` type. If we -wanted to permit conversion between `isize` and `usize`, we might -implement `Convert` like so: - -```rust -impl Convert for isize { ... } // isize -> usize -impl Convert for usize { ... } // usize -> isize -``` - -Now imagine there is some code like the following: - -```rust -let x: isize = ...; -let y = x.convert(); -``` - -The call to convert will generate a trait reference `Convert<$Y> for -isize`, where `$Y` is the type variable representing the type of -`y`. When we match this against the two impls we can see, we will find -that only one remains: `Convert for isize`. Therefore, we can -select this impl, which will cause the type of `$Y` to be unified to -`usize`. (Note that while assembling candidates, we do the initial -unifications in a transaction, so that they don't affect one another.) - -There are tests to this effect in src/test/run-pass: - - traits-multidispatch-infer-convert-source-and-target.rs - traits-multidispatch-infer-convert-target.rs - -#### Winnowing: Resolving ambiguities - -But what happens if there are multiple impls where all the types -unify? Consider this example: - -```rust -trait Get { - fn get(&self) -> Self; -} - -impl Get for T { - fn get(&self) -> T { *self } -} - -impl Get for Box { - fn get(&self) -> Box { box get_it(&**self) } -} -``` - -What happens when we invoke `get_it(&box 1_u16)`, for example? In this -case, the `Self` type is `Box` -- that unifies with both impls, -because the first applies to all types, and the second to all -boxes. In the olden days we'd have called this ambiguous. But what we -do now is do a second *winnowing* pass that considers where clauses -and attempts to remove candidates -- in this case, the first impl only -applies if `Box : Copy`, which doesn't hold. After winnowing, -then, we are left with just one candidate, so we can proceed. There is -a test of this in `src/test/run-pass/traits-conditional-dispatch.rs`. - -#### Matching - -The subroutines that decide whether a particular impl/where-clause/etc -applies to a particular obligation. At the moment, this amounts to -unifying the self types, but in the future we may also recursively -consider some of the nested obligations, in the case of an impl. - -#### Lifetimes and selection - -Because of how that lifetime inference works, it is not possible to -give back immediate feedback as to whether a unification or subtype -relationship between lifetimes holds or not. Therefore, lifetime -matching is *not* considered during selection. This is reflected in -the fact that subregion assignment is infallible. This may yield -lifetime constraints that will later be found to be in error (in -contrast, the non-lifetime-constraints have already been checked -during selection and can never cause an error, though naturally they -may lead to other errors downstream). - -#### Where clauses - -Besides an impl, the other major way to resolve an obligation is via a -where clause. The selection process is always given a *parameter -environment* which contains a list of where clauses, which are -basically obligations that can assume are satisfiable. We will iterate -over that list and check whether our current obligation can be found -in that list, and if so it is considered satisfied. More precisely, we -want to check whether there is a where-clause obligation that is for -the same trait (or some subtrait) and for which the self types match, -using the definition of *matching* given above. - -Consider this simple example: - - trait A1 { ... } - trait A2 : A1 { ... } - - trait B { ... } - - fn foo { ... } - -Clearly we can use methods offered by `A1`, `A2`, or `B` within the -body of `foo`. In each case, that will incur an obligation like `X : -A1` or `X : A2`. The parameter environment will contain two -where-clauses, `X : A2` and `X : B`. For each obligation, then, we -search this list of where-clauses. To resolve an obligation `X:A1`, -we would note that `X:A2` implies that `X:A1`. - -### Confirmation - -Confirmation unifies the output type parameters of the trait with the -values found in the obligation, possibly yielding a type error. If we -return to our example of the `Convert` trait from the previous -section, confirmation is where an error would be reported, because the -impl specified that `T` would be `usize`, but the obligation reported -`char`. Hence the result of selection would be an error. - -### Selection during translation - -During type checking, we do not store the results of trait selection. -We simply wish to verify that trait selection will succeed. Then -later, at trans time, when we have all concrete types available, we -can repeat the trait selection. In this case, we do not consider any -where-clauses to be in scope. We know that therefore each resolution -will resolve to a particular impl. - -One interesting twist has to do with nested obligations. In general, in trans, -we only need to do a "shallow" selection for an obligation. That is, we wish to -identify which impl applies, but we do not (yet) need to decide how to select -any nested obligations. Nonetheless, we *do* currently do a complete resolution, -and that is because it can sometimes inform the results of type inference. That is, -we do not have the full substitutions in terms of the type variables of the impl available -to us, so we must run trait selection to figure everything out. - -Here is an example: - - trait Foo { ... } - impl> Foo for Vec { ... } - - impl Bar for isize { ... } - -After one shallow round of selection for an obligation like `Vec -: Foo`, we would know which impl we want, and we would know that -`T=isize`, but we do not know the type of `U`. We must select the -nested obligation `isize : Bar` to find out that `U=usize`. - -It would be good to only do *just as much* nested resolution as -necessary. Currently, though, we just do a full resolution. - -# Higher-ranked trait bounds - -One of the more subtle concepts at work are *higher-ranked trait -bounds*. An example of such a bound is `for<'a> MyTrait<&'a isize>`. -Let's walk through how selection on higher-ranked trait references -works. - -## Basic matching and skolemization leaks - -Let's walk through the test `compile-fail/hrtb-just-for-static.rs` to see -how it works. The test starts with the trait `Foo`: - -```rust -trait Foo { - fn foo(&self, x: X) { } -} -``` - -Let's say we have a function `want_hrtb` that wants a type which -implements `Foo<&'a isize>` for any `'a`: - -```rust -fn want_hrtb() where T : for<'a> Foo<&'a isize> { ... } -``` - -Now we have a struct `AnyInt` that implements `Foo<&'a isize>` for any -`'a`: - -```rust -struct AnyInt; -impl<'a> Foo<&'a isize> for AnyInt { } -``` - -And the question is, does `AnyInt : for<'a> Foo<&'a isize>`? We want the -answer to be yes. The algorithm for figuring it out is closely related -to the subtyping for higher-ranked types (which is described in -`middle::infer::higher_ranked::doc`, but also in a [paper by SPJ] that -I recommend you read). - -1. Skolemize the obligation. -2. Match the impl against the skolemized obligation. -3. Check for skolemization leaks. - -[paper by SPJ]: http://research.microsoft.com/en-us/um/people/simonpj/papers/higher-rank/ - -So let's work through our example. The first thing we would do is to -skolemize the obligation, yielding `AnyInt : Foo<&'0 isize>` (here `'0` -represents skolemized region #0). Note that now have no quantifiers; -in terms of the compiler type, this changes from a `ty::PolyTraitRef` -to a `TraitRef`. We would then create the `TraitRef` from the impl, -using fresh variables for it's bound regions (and thus getting -`Foo<&'$a isize>`, where `'$a` is the inference variable for `'a`). Next -we relate the two trait refs, yielding a graph with the constraint -that `'0 == '$a`. Finally, we check for skolemization "leaks" -- a -leak is basically any attempt to relate a skolemized region to another -skolemized region, or to any region that pre-existed the impl match. -The leak check is done by searching from the skolemized region to find -the set of regions that it is related to in any way. This is called -the "taint" set. To pass the check, that set must consist *solely* of -itself and region variables from the impl. If the taint set includes -any other region, then the match is a failure. In this case, the taint -set for `'0` is `{'0, '$a}`, and hence the check will succeed. - -Let's consider a failure case. Imagine we also have a struct - -```rust -struct StaticInt; -impl Foo<&'static isize> for StaticInt; -``` - -We want the obligation `StaticInt : for<'a> Foo<&'a isize>` to be -considered unsatisfied. The check begins just as before. `'a` is -skolemized to `'0` and the impl trait reference is instantiated to -`Foo<&'static isize>`. When we relate those two, we get a constraint -like `'static == '0`. This means that the taint set for `'0` is `{'0, -'static}`, which fails the leak check. - -## Higher-ranked trait obligations - -Once the basic matching is done, we get to another interesting topic: -how to deal with impl obligations. I'll work through a simple example -here. Imagine we have the traits `Foo` and `Bar` and an associated impl: - -``` -trait Foo { - fn foo(&self, x: X) { } -} - -trait Bar { - fn bar(&self, x: X) { } -} - -impl Foo for F - where F : Bar -{ -} -``` - -Now let's say we have a obligation `for<'a> Foo<&'a isize>` and we match -this impl. What obligation is generated as a result? We want to get -`for<'a> Bar<&'a isize>`, but how does that happen? - -After the matching, we are in a position where we have a skolemized -substitution like `X => &'0 isize`. If we apply this substitution to the -impl obligations, we get `F : Bar<&'0 isize>`. Obviously this is not -directly usable because the skolemized region `'0` cannot leak out of -our computation. - -What we do is to create an inverse mapping from the taint set of `'0` -back to the original bound region (`'a`, here) that `'0` resulted -from. (This is done in `higher_ranked::plug_leaks`). We know that the -leak check passed, so this taint set consists solely of the skolemized -region itself plus various intermediate region variables. We then walk -the trait-reference and convert every region in that taint set back to -a late-bound region, so in this case we'd wind up with `for<'a> F : -Bar<&'a isize>`. - -# Caching and subtle considerations therewith - -In general we attempt to cache the results of trait selection. This -is a somewhat complex process. Part of the reason for this is that we -want to be able to cache results even when all the types in the trait -reference are not fully known. In that case, it may happen that the -trait selection process is also influencing type variables, so we have -to be able to not only cache the *result* of the selection process, -but *replay* its effects on the type variables. - -## An example - -The high-level idea of how the cache works is that we first replace -all unbound inference variables with skolemized versions. Therefore, -if we had a trait reference `usize : Foo<$1>`, where `$n` is an unbound -inference variable, we might replace it with `usize : Foo<%0>`, where -`%n` is a skolemized type. We would then look this up in the cache. -If we found a hit, the hit would tell us the immediate next step to -take in the selection process: i.e., apply impl #22, or apply where -clause `X : Foo`. Let's say in this case there is no hit. -Therefore, we search through impls and where clauses and so forth, and -we come to the conclusion that the only possible impl is this one, -with def-id 22: - - impl Foo for usize { ... } // Impl #22 - -We would then record in the cache `usize : Foo<%0> ==> -ImplCandidate(22)`. Next we would confirm `ImplCandidate(22)`, which -would (as a side-effect) unify `$1` with `isize`. - -Now, at some later time, we might come along and see a `usize : -Foo<$3>`. When skolemized, this would yield `usize : Foo<%0>`, just as -before, and hence the cache lookup would succeed, yielding -`ImplCandidate(22)`. We would confirm `ImplCandidate(22)` which would -(as a side-effect) unify `$3` with `isize`. - -## Where clauses and the local vs global cache - -One subtle interaction is that the results of trait lookup will vary -depending on what where clauses are in scope. Therefore, we actually -have *two* caches, a local and a global cache. The local cache is -attached to the `ParameterEnvironment` and the global cache attached -to the `tcx`. We use the local cache whenever the result might depend -on the where clauses that are in scope. The determination of which -cache to use is done by the method `pick_candidate_cache` in -`select.rs`. At the moment, we use a very simple, conservative rule: -if there are any where-clauses in scope, then we use the local cache. -We used to try and draw finer-grained distinctions, but that led to a -serious of annoying and weird bugs like #22019 and #18290. This simple -rule seems to be pretty clearly safe and also still retains a very -high hit rate (~95% when compiling rustc). - -# Specialization - -Defined in the `specialize` module. - -The basic strategy is to build up a *specialization graph* during -coherence checking. Insertion into the graph locates the right place -to put an impl in the specialization hierarchy; if there is no right -place (due to partial overlap but no containment), you get an overlap -error. Specialization is consulted when selecting an impl (of course), -and the graph is consulted when propagating defaults down the -specialization hierarchy. - -You might expect that the specialization graph would be used during -selection -- i.e., when actually performing specialization. This is -not done for two reasons: - -- It's merely an optimization: given a set of candidates that apply, - we can determine the most specialized one by comparing them directly - for specialization, rather than consulting the graph. Given that we - also cache the results of selection, the benefit of this - optimization is questionable. - -- To build the specialization graph in the first place, we need to use - selection (because we need to determine whether one impl specializes - another). Dealing with this reentrancy would require some additional - mode switch for selection. Given that there seems to be no strong - reason to use the graph anyway, we stick with a simpler approach in - selection, and use the graph only for propagating default - implementations. - -Trait impl selection can succeed even when multiple impls can apply, -as long as they are part of the same specialization family. In that -case, it returns a *single* impl on success -- this is the most -specialized impl *known* to apply. However, if there are any inference -variables in play, the returned impl may not be the actual impl we -will use at trans time. Thus, we take special care to avoid projecting -associated types unless either (1) the associated type does not use -`default` and thus cannot be overridden or (2) all input types are -known concretely. diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs deleted file mode 100644 index 547cb71f234..00000000000 --- a/src/librustc/middle/traits/coherence.rs +++ /dev/null @@ -1,299 +0,0 @@ -// Copyright 2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! See `README.md` for high-level documentation - -use super::{SelectionContext, Obligation, ObligationCause}; - -use middle::cstore::LOCAL_CRATE; -use middle::def_id::DefId; -use middle::ty::subst::TypeSpace; -use middle::ty::{self, Ty, TyCtxt}; -use middle::infer::{self, InferCtxt, TypeOrigin}; -use syntax::codemap::DUMMY_SP; - -#[derive(Copy, Clone)] -struct InferIsLocal(bool); - -/// If there are types that satisfy both impls, returns a suitably-freshened -/// `ImplHeader` with those types substituted -pub fn overlapping_impls<'cx, 'tcx>(infcx: &InferCtxt<'cx, 'tcx>, - impl1_def_id: DefId, - impl2_def_id: DefId) - -> Option> -{ - debug!("impl_can_satisfy(\ - impl1_def_id={:?}, \ - impl2_def_id={:?})", - impl1_def_id, - impl2_def_id); - - let selcx = &mut SelectionContext::intercrate(infcx); - overlap(selcx, impl1_def_id, impl2_def_id) -} - -/// Can both impl `a` and impl `b` be satisfied by a common type (including -/// `where` clauses)? If so, returns an `ImplHeader` that unifies the two impls. -fn overlap<'cx, 'tcx>(selcx: &mut SelectionContext<'cx, 'tcx>, - a_def_id: DefId, - b_def_id: DefId) - -> Option> -{ - debug!("overlap(a_def_id={:?}, b_def_id={:?})", - a_def_id, - b_def_id); - - let a_impl_header = ty::ImplHeader::with_fresh_ty_vars(selcx, a_def_id); - let b_impl_header = ty::ImplHeader::with_fresh_ty_vars(selcx, b_def_id); - - debug!("overlap: a_impl_header={:?}", a_impl_header); - debug!("overlap: b_impl_header={:?}", b_impl_header); - - // Do `a` and `b` unify? If not, no overlap. - if let Err(_) = infer::mk_eq_impl_headers(selcx.infcx(), - true, - TypeOrigin::Misc(DUMMY_SP), - &a_impl_header, - &b_impl_header) { - return None; - } - - debug!("overlap: unification check succeeded"); - - // Are any of the obligations unsatisfiable? If so, no overlap. - let infcx = selcx.infcx(); - let opt_failing_obligation = - a_impl_header.predicates - .iter() - .chain(&b_impl_header.predicates) - .map(|p| infcx.resolve_type_vars_if_possible(p)) - .map(|p| Obligation { cause: ObligationCause::dummy(), - recursion_depth: 0, - predicate: p }) - .find(|o| !selcx.evaluate_obligation(o)); - - if let Some(failing_obligation) = opt_failing_obligation { - debug!("overlap: obligation unsatisfiable {:?}", failing_obligation); - return None - } - - Some(selcx.infcx().resolve_type_vars_if_possible(&a_impl_header)) -} - -pub fn trait_ref_is_knowable<'tcx>(tcx: &TyCtxt<'tcx>, trait_ref: &ty::TraitRef<'tcx>) -> bool -{ - debug!("trait_ref_is_knowable(trait_ref={:?})", trait_ref); - - // if the orphan rules pass, that means that no ancestor crate can - // impl this, so it's up to us. - if orphan_check_trait_ref(tcx, trait_ref, InferIsLocal(false)).is_ok() { - debug!("trait_ref_is_knowable: orphan check passed"); - return true; - } - - // if the trait is not marked fundamental, then it's always possible that - // an ancestor crate will impl this in the future, if they haven't - // already - if - trait_ref.def_id.krate != LOCAL_CRATE && - !tcx.has_attr(trait_ref.def_id, "fundamental") - { - debug!("trait_ref_is_knowable: trait is neither local nor fundamental"); - return false; - } - - // find out when some downstream (or cousin) crate could impl this - // trait-ref, presuming that all the parameters were instantiated - // with downstream types. If not, then it could only be - // implemented by an upstream crate, which means that the impl - // must be visible to us, and -- since the trait is fundamental - // -- we can test. - orphan_check_trait_ref(tcx, trait_ref, InferIsLocal(true)).is_err() -} - -pub enum OrphanCheckErr<'tcx> { - NoLocalInputType, - UncoveredTy(Ty<'tcx>), -} - -/// Checks the coherence orphan rules. `impl_def_id` should be the -/// def-id of a trait impl. To pass, either the trait must be local, or else -/// two conditions must be satisfied: -/// -/// 1. All type parameters in `Self` must be "covered" by some local type constructor. -/// 2. Some local type must appear in `Self`. -pub fn orphan_check<'tcx>(tcx: &TyCtxt<'tcx>, - impl_def_id: DefId) - -> Result<(), OrphanCheckErr<'tcx>> -{ - debug!("orphan_check({:?})", impl_def_id); - - // We only except this routine to be invoked on implementations - // of a trait, not inherent implementations. - let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); - debug!("orphan_check: trait_ref={:?}", trait_ref); - - // If the *trait* is local to the crate, ok. - if trait_ref.def_id.is_local() { - debug!("trait {:?} is local to current crate", - trait_ref.def_id); - return Ok(()); - } - - orphan_check_trait_ref(tcx, &trait_ref, InferIsLocal(false)) -} - -fn orphan_check_trait_ref<'tcx>(tcx: &TyCtxt<'tcx>, - trait_ref: &ty::TraitRef<'tcx>, - infer_is_local: InferIsLocal) - -> Result<(), OrphanCheckErr<'tcx>> -{ - debug!("orphan_check_trait_ref(trait_ref={:?}, infer_is_local={})", - trait_ref, infer_is_local.0); - - // First, create an ordered iterator over all the type parameters to the trait, with the self - // type appearing first. - let input_tys = Some(trait_ref.self_ty()); - let input_tys = input_tys.iter().chain(trait_ref.substs.types.get_slice(TypeSpace)); - - // Find the first input type that either references a type parameter OR - // some local type. - for input_ty in input_tys { - if ty_is_local(tcx, input_ty, infer_is_local) { - debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty); - - // First local input type. Check that there are no - // uncovered type parameters. - let uncovered_tys = uncovered_tys(tcx, input_ty, infer_is_local); - for uncovered_ty in uncovered_tys { - if let Some(param) = uncovered_ty.walk().find(|t| is_type_parameter(t)) { - debug!("orphan_check_trait_ref: uncovered type `{:?}`", param); - return Err(OrphanCheckErr::UncoveredTy(param)); - } - } - - // OK, found local type, all prior types upheld invariant. - return Ok(()); - } - - // Otherwise, enforce invariant that there are no type - // parameters reachable. - if !infer_is_local.0 { - if let Some(param) = input_ty.walk().find(|t| is_type_parameter(t)) { - debug!("orphan_check_trait_ref: uncovered type `{:?}`", param); - return Err(OrphanCheckErr::UncoveredTy(param)); - } - } - } - - // If we exit above loop, never found a local type. - debug!("orphan_check_trait_ref: no local type"); - return Err(OrphanCheckErr::NoLocalInputType); -} - -fn uncovered_tys<'tcx>(tcx: &TyCtxt<'tcx>, - ty: Ty<'tcx>, - infer_is_local: InferIsLocal) - -> Vec> -{ - if ty_is_local_constructor(tcx, ty, infer_is_local) { - vec![] - } else if fundamental_ty(tcx, ty) { - ty.walk_shallow() - .flat_map(|t| uncovered_tys(tcx, t, infer_is_local)) - .collect() - } else { - vec![ty] - } -} - -fn is_type_parameter<'tcx>(ty: Ty<'tcx>) -> bool { - match ty.sty { - // FIXME(#20590) straighten story about projection types - ty::TyProjection(..) | ty::TyParam(..) => true, - _ => false, - } -} - -fn ty_is_local<'tcx>(tcx: &TyCtxt<'tcx>, ty: Ty<'tcx>, infer_is_local: InferIsLocal) -> bool -{ - ty_is_local_constructor(tcx, ty, infer_is_local) || - fundamental_ty(tcx, ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, infer_is_local)) -} - -fn fundamental_ty<'tcx>(tcx: &TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool -{ - match ty.sty { - ty::TyBox(..) | ty::TyRef(..) => - true, - ty::TyEnum(def, _) | ty::TyStruct(def, _) => - def.is_fundamental(), - ty::TyTrait(ref data) => - tcx.has_attr(data.principal_def_id(), "fundamental"), - _ => - false - } -} - -fn ty_is_local_constructor<'tcx>(tcx: &TyCtxt<'tcx>, - ty: Ty<'tcx>, - infer_is_local: InferIsLocal) - -> bool -{ - debug!("ty_is_local_constructor({:?})", ty); - - match ty.sty { - ty::TyBool | - ty::TyChar | - ty::TyInt(..) | - ty::TyUint(..) | - ty::TyFloat(..) | - ty::TyStr | - ty::TyFnDef(..) | - ty::TyFnPtr(_) | - ty::TyArray(..) | - ty::TySlice(..) | - ty::TyRawPtr(..) | - ty::TyRef(..) | - ty::TyTuple(..) | - ty::TyParam(..) | - ty::TyProjection(..) => { - false - } - - ty::TyInfer(..) => { - infer_is_local.0 - } - - ty::TyEnum(def, _) | - ty::TyStruct(def, _) => { - def.did.is_local() - } - - ty::TyBox(_) => { // Box - let krate = tcx.lang_items.owned_box().map(|d| d.krate); - krate == Some(LOCAL_CRATE) - } - - ty::TyTrait(ref tt) => { - tt.principal_def_id().is_local() - } - - ty::TyError => { - true - } - - ty::TyClosure(..) => { - tcx.sess.bug( - &format!("ty_is_local invoked on unexpected type: {:?}", - ty)) - } - } -} diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs deleted file mode 100644 index dd051471a4d..00000000000 --- a/src/librustc/middle/traits/error_reporting.rs +++ /dev/null @@ -1,807 +0,0 @@ -// Copyright 2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::{ - FulfillmentError, - FulfillmentErrorCode, - MismatchedProjectionTypes, - Obligation, - ObligationCauseCode, - OutputTypeParameterMismatch, - TraitNotObjectSafe, - PredicateObligation, - SelectionError, - ObjectSafetyViolation, - MethodViolationCode, - object_safety_violations, -}; - -use fmt_macros::{Parser, Piece, Position}; -use middle::def_id::DefId; -use middle::infer::InferCtxt; -use middle::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable}; -use middle::ty::fast_reject; -use util::nodemap::{FnvHashMap, FnvHashSet}; - -use std::cmp; -use std::fmt; -use syntax::attr::{AttributeMethods, AttrMetaMethods}; -use syntax::codemap::Span; -use syntax::errors::DiagnosticBuilder; - -#[derive(Debug, PartialEq, Eq, Hash)] -pub struct TraitErrorKey<'tcx> { - span: Span, - predicate: ty::Predicate<'tcx> -} - -impl<'tcx> TraitErrorKey<'tcx> { - fn from_error<'a>(infcx: &InferCtxt<'a, 'tcx>, - e: &FulfillmentError<'tcx>) -> Self { - let predicate = - infcx.resolve_type_vars_if_possible(&e.obligation.predicate); - TraitErrorKey { - span: e.obligation.cause.span, - predicate: infcx.tcx.erase_regions(&predicate) - } - } -} - -pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, - errors: &Vec>) { - for error in errors { - report_fulfillment_error(infcx, error); - } -} - -fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, - error: &FulfillmentError<'tcx>) { - let error_key = TraitErrorKey::from_error(infcx, error); - debug!("report_fulfillment_errors({:?}) - key={:?}", - error, error_key); - if !infcx.reported_trait_errors.borrow_mut().insert(error_key) { - debug!("report_fulfillment_errors: skipping duplicate"); - return; - } - match error.code { - FulfillmentErrorCode::CodeSelectionError(ref e) => { - report_selection_error(infcx, &error.obligation, e); - } - FulfillmentErrorCode::CodeProjectionError(ref e) => { - report_projection_error(infcx, &error.obligation, e); - } - FulfillmentErrorCode::CodeAmbiguity => { - maybe_report_ambiguity(infcx, &error.obligation); - } - } -} - -pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, - obligation: &PredicateObligation<'tcx>, - error: &MismatchedProjectionTypes<'tcx>) -{ - let predicate = - infcx.resolve_type_vars_if_possible(&obligation.predicate); - - // The TyError created by normalize_to_error can end up being unified - // into all obligations: for example, if our obligation is something - // like `$X = <() as Foo<$X>>::Out` and () does not implement Foo<_>, - // then $X will be unified with TyError, but the error still needs to be - // reported. - if !infcx.tcx.sess.has_errors() || !predicate.references_error() { - let mut err = struct_span_err!(infcx.tcx.sess, obligation.cause.span, E0271, - "type mismatch resolving `{}`: {}", - predicate, - error.err); - note_obligation_cause(infcx, &mut err, obligation); - err.emit(); - } -} - -fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, - trait_ref: &TraitRef<'tcx>, - span: Span) -> Option { - let def_id = trait_ref.def_id; - let mut report = None; - for item in infcx.tcx.get_attrs(def_id).iter() { - if item.check_name("rustc_on_unimplemented") { - let err_sp = item.meta().span.substitute_dummy(span); - let def = infcx.tcx.lookup_trait_def(def_id); - let trait_str = def.trait_ref.to_string(); - if let Some(ref istring) = item.value_str() { - let mut generic_map = def.generics.types.iter_enumerated() - .map(|(param, i, gen)| { - (gen.name.as_str().to_string(), - trait_ref.substs.types.get(param, i) - .to_string()) - }).collect::>(); - generic_map.insert("Self".to_string(), - trait_ref.self_ty().to_string()); - let parser = Parser::new(&istring); - let mut errored = false; - let err: String = parser.filter_map(|p| { - match p { - Piece::String(s) => Some(s), - Piece::NextArgument(a) => match a.position { - Position::ArgumentNamed(s) => match generic_map.get(s) { - Some(val) => Some(val), - None => { - span_err!(infcx.tcx.sess, err_sp, E0272, - "the #[rustc_on_unimplemented] \ - attribute on \ - trait definition for {} refers to \ - non-existent type parameter {}", - trait_str, s); - errored = true; - None - } - }, - _ => { - span_err!(infcx.tcx.sess, err_sp, E0273, - "the #[rustc_on_unimplemented] \ - attribute on \ - trait definition for {} must have named \ - format arguments, \ - eg `#[rustc_on_unimplemented = \ - \"foo {{T}}\"]`", - trait_str); - errored = true; - None - } - } - } - }).collect(); - // Report only if the format string checks out - if !errored { - report = Some(err); - } - } else { - span_err!(infcx.tcx.sess, err_sp, E0274, - "the #[rustc_on_unimplemented] attribute on \ - trait definition for {} must have a value, \ - eg `#[rustc_on_unimplemented = \"foo\"]`", - trait_str); - } - break; - } - } - report -} - -/// Reports that an overflow has occurred and halts compilation. We -/// halt compilation unconditionally because it is important that -/// overflows never be masked -- they basically represent computations -/// whose result could not be truly determined and thus we can't say -/// if the program type checks or not -- and they are unusual -/// occurrences in any case. -pub fn report_overflow_error<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, - obligation: &Obligation<'tcx, T>, - suggest_increasing_limit: bool) - -> ! - where T: fmt::Display + TypeFoldable<'tcx> -{ - let predicate = - infcx.resolve_type_vars_if_possible(&obligation.predicate); - let mut err = struct_span_err!(infcx.tcx.sess, obligation.cause.span, E0275, - "overflow evaluating the requirement `{}`", - predicate); - - if suggest_increasing_limit { - suggest_new_overflow_limit(infcx.tcx, &mut err, obligation.cause.span); - } - - note_obligation_cause(infcx, &mut err, obligation); - - err.emit(); - infcx.tcx.sess.abort_if_errors(); - unreachable!(); -} - -/// Reports that a cycle was detected which led to overflow and halts -/// compilation. This is equivalent to `report_overflow_error` except -/// that we can give a more helpful error message (and, in particular, -/// we do not suggest increasing the overflow limit, which is not -/// going to help). -pub fn report_overflow_error_cycle<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, - cycle: &Vec>) - -> ! -{ - assert!(cycle.len() > 1); - - debug!("report_overflow_error_cycle(cycle length = {})", cycle.len()); - - let cycle = infcx.resolve_type_vars_if_possible(cycle); - - debug!("report_overflow_error_cycle: cycle={:?}", cycle); - - assert_eq!(&cycle[0].predicate, &cycle.last().unwrap().predicate); - - try_report_overflow_error_type_of_infinite_size(infcx, &cycle); - report_overflow_error(infcx, &cycle[0], false); -} - -/// If a cycle results from evaluated whether something is Sized, that -/// is a particular special case that always results from a struct or -/// enum definition that lacks indirection (e.g., `struct Foo { x: Foo -/// }`). We wish to report a targeted error for this case. -pub fn try_report_overflow_error_type_of_infinite_size<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, - cycle: &[PredicateObligation<'tcx>]) -{ - let sized_trait = match infcx.tcx.lang_items.sized_trait() { - Some(v) => v, - None => return, - }; - let top_is_sized = { - match cycle[0].predicate { - ty::Predicate::Trait(ref data) => data.def_id() == sized_trait, - _ => false, - } - }; - if !top_is_sized { - return; - } - - // The only way to have a type of infinite size is to have, - // somewhere, a struct/enum type involved. Identify all such types - // and report the cycle to the user. - - let struct_enum_tys: Vec<_> = - cycle.iter() - .flat_map(|obligation| match obligation.predicate { - ty::Predicate::Trait(ref data) => { - assert_eq!(data.def_id(), sized_trait); - let self_ty = data.skip_binder().trait_ref.self_ty(); // (*) - // (*) ok to skip binder because this is just - // error reporting and regions don't really - // matter - match self_ty.sty { - ty::TyEnum(..) | ty::TyStruct(..) => Some(self_ty), - _ => None, - } - } - _ => { - infcx.tcx.sess.span_bug(obligation.cause.span, - &format!("Sized cycle involving non-trait-ref: {:?}", - obligation.predicate)); - } - }) - .collect(); - - assert!(!struct_enum_tys.is_empty()); - - // This is a bit tricky. We want to pick a "main type" in the - // listing that is local to the current crate, so we can give a - // good span to the user. But it might not be the first one in our - // cycle list. So find the first one that is local and then - // rotate. - let (main_index, main_def_id) = - struct_enum_tys.iter() - .enumerate() - .filter_map(|(index, ty)| match ty.sty { - ty::TyEnum(adt_def, _) | ty::TyStruct(adt_def, _) - if adt_def.did.is_local() => - Some((index, adt_def.did)), - _ => - None, - }) - .next() - .unwrap(); // should always be SOME local type involved! - - // Rotate so that the "main" type is at index 0. - let struct_enum_tys: Vec<_> = - struct_enum_tys.iter() - .cloned() - .skip(main_index) - .chain(struct_enum_tys.iter().cloned().take(main_index)) - .collect(); - - let tcx = infcx.tcx; - let mut err = recursive_type_with_infinite_size_error(tcx, main_def_id); - let len = struct_enum_tys.len(); - if len > 2 { - let span = tcx.map.span_if_local(main_def_id).unwrap(); - err.fileline_note(span, - &format!("type `{}` is embedded within `{}`...", - struct_enum_tys[0], - struct_enum_tys[1])); - for &next_ty in &struct_enum_tys[1..len-1] { - err.fileline_note(span, - &format!("...which in turn is embedded within `{}`...", next_ty)); - } - err.fileline_note(span, - &format!("...which in turn is embedded within `{}`, \ - completing the cycle.", - struct_enum_tys[len-1])); - } - err.emit(); - infcx.tcx.sess.abort_if_errors(); - unreachable!(); -} - -pub fn recursive_type_with_infinite_size_error<'tcx>(tcx: &TyCtxt<'tcx>, - type_def_id: DefId) - -> DiagnosticBuilder<'tcx> -{ - assert!(type_def_id.is_local()); - let span = tcx.map.span_if_local(type_def_id).unwrap(); - let mut err = struct_span_err!(tcx.sess, span, E0072, "recursive type `{}` has infinite size", - tcx.item_path_str(type_def_id)); - err.fileline_help(span, &format!("insert indirection (e.g., a `Box`, `Rc`, or `&`) \ - at some point to make `{}` representable", - tcx.item_path_str(type_def_id))); - err -} - -pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, - obligation: &PredicateObligation<'tcx>, - error: &SelectionError<'tcx>) -{ - match *error { - SelectionError::Unimplemented => { - if let ObligationCauseCode::CompareImplMethodObligation = obligation.cause.code { - span_err!( - infcx.tcx.sess, obligation.cause.span, E0276, - "the requirement `{}` appears on the impl \ - method but not on the corresponding trait method", - obligation.predicate); - } else { - match obligation.predicate { - ty::Predicate::Trait(ref trait_predicate) => { - let trait_predicate = - infcx.resolve_type_vars_if_possible(trait_predicate); - - if !infcx.tcx.sess.has_errors() || !trait_predicate.references_error() { - let trait_ref = trait_predicate.to_poly_trait_ref(); - let mut err = struct_span_err!( - infcx.tcx.sess, obligation.cause.span, E0277, - "the trait `{}` is not implemented for the type `{}`", - trait_ref, trait_ref.self_ty()); - - // Check if it has a custom "#[rustc_on_unimplemented]" - // error message, report with that message if it does - let custom_note = report_on_unimplemented(infcx, &trait_ref.0, - obligation.cause.span); - if let Some(s) = custom_note { - err.fileline_note(obligation.cause.span, &s); - } else { - let simp = fast_reject::simplify_type(infcx.tcx, - trait_ref.self_ty(), - true); - let mut impl_candidates = Vec::new(); - let trait_def = infcx.tcx.lookup_trait_def(trait_ref.def_id()); - - match simp { - Some(simp) => trait_def.for_each_impl(infcx.tcx, |def_id| { - let imp = infcx.tcx.impl_trait_ref(def_id).unwrap(); - let imp_simp = fast_reject::simplify_type(infcx.tcx, - imp.self_ty(), - true); - if let Some(imp_simp) = imp_simp { - if simp != imp_simp { - return; - } - } - impl_candidates.push(imp); - }), - None => trait_def.for_each_impl(infcx.tcx, |def_id| { - impl_candidates.push( - infcx.tcx.impl_trait_ref(def_id).unwrap()); - }) - }; - - if impl_candidates.len() > 0 { - err.fileline_help( - obligation.cause.span, - &format!("the following implementations were found:")); - - let end = cmp::min(4, impl_candidates.len()); - for candidate in &impl_candidates[0..end] { - err.fileline_help(obligation.cause.span, - &format!(" {:?}", candidate)); - } - if impl_candidates.len() > 4 { - err.fileline_help(obligation.cause.span, - &format!("and {} others", - impl_candidates.len()-4)); - } - } - } - note_obligation_cause(infcx, &mut err, obligation); - err.emit(); - } - }, - ty::Predicate::Equate(ref predicate) => { - let predicate = infcx.resolve_type_vars_if_possible(predicate); - let err = infcx.equality_predicate(obligation.cause.span, - &predicate).err().unwrap(); - let mut err = struct_span_err!( - infcx.tcx.sess, obligation.cause.span, E0278, - "the requirement `{}` is not satisfied (`{}`)", - predicate, - err); - note_obligation_cause(infcx, &mut err, obligation); - err.emit(); - } - - ty::Predicate::RegionOutlives(ref predicate) => { - let predicate = infcx.resolve_type_vars_if_possible(predicate); - let err = infcx.region_outlives_predicate(obligation.cause.span, - &predicate).err().unwrap(); - let mut err = struct_span_err!( - infcx.tcx.sess, obligation.cause.span, E0279, - "the requirement `{}` is not satisfied (`{}`)", - predicate, - err); - note_obligation_cause(infcx, &mut err, obligation); - err.emit(); - } - - ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => { - let predicate = - infcx.resolve_type_vars_if_possible(&obligation.predicate); - let mut err = struct_span_err!( - infcx.tcx.sess, obligation.cause.span, E0280, - "the requirement `{}` is not satisfied", - predicate); - note_obligation_cause(infcx, &mut err, obligation); - err.emit(); - } - - ty::Predicate::ObjectSafe(trait_def_id) => { - let violations = object_safety_violations( - infcx.tcx, trait_def_id); - let mut err = report_object_safety_error(infcx.tcx, - obligation.cause.span, - trait_def_id, - violations); - note_obligation_cause(infcx, &mut err, obligation); - err.emit(); - } - - ty::Predicate::WellFormed(ty) => { - // WF predicates cannot themselves make - // errors. They can only block due to - // ambiguity; otherwise, they always - // degenerate into other obligations - // (which may fail). - infcx.tcx.sess.span_bug( - obligation.cause.span, - &format!("WF predicate not satisfied for {:?}", ty)); - } - } - } - } - - OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => { - let expected_trait_ref = infcx.resolve_type_vars_if_possible(&*expected_trait_ref); - let actual_trait_ref = infcx.resolve_type_vars_if_possible(&*actual_trait_ref); - if !actual_trait_ref.self_ty().references_error() { - let mut err = struct_span_err!( - infcx.tcx.sess, obligation.cause.span, E0281, - "type mismatch: the type `{}` implements the trait `{}`, \ - but the trait `{}` is required ({})", - expected_trait_ref.self_ty(), - expected_trait_ref, - actual_trait_ref, - e); - note_obligation_cause(infcx, &mut err, obligation); - err.emit(); - } - } - - TraitNotObjectSafe(did) => { - let violations = object_safety_violations(infcx.tcx, did); - let mut err = report_object_safety_error(infcx.tcx, obligation.cause.span, did, - violations); - note_obligation_cause(infcx, &mut err, obligation); - err.emit(); - } - } -} - -pub fn report_object_safety_error<'tcx>(tcx: &TyCtxt<'tcx>, - span: Span, - trait_def_id: DefId, - violations: Vec) - -> DiagnosticBuilder<'tcx> -{ - let mut err = struct_span_err!( - tcx.sess, span, E0038, - "the trait `{}` cannot be made into an object", - tcx.item_path_str(trait_def_id)); - - let mut reported_violations = FnvHashSet(); - for violation in violations { - if !reported_violations.insert(violation.clone()) { - continue; - } - match violation { - ObjectSafetyViolation::SizedSelf => { - err.fileline_note( - span, - "the trait cannot require that `Self : Sized`"); - } - - ObjectSafetyViolation::SupertraitSelf => { - err.fileline_note( - span, - "the trait cannot use `Self` as a type parameter \ - in the supertrait listing"); - } - - ObjectSafetyViolation::Method(method, - MethodViolationCode::StaticMethod) => { - err.fileline_note( - span, - &format!("method `{}` has no receiver", - method.name)); - } - - ObjectSafetyViolation::Method(method, - MethodViolationCode::ReferencesSelf) => { - err.fileline_note( - span, - &format!("method `{}` references the `Self` type \ - in its arguments or return type", - method.name)); - } - - ObjectSafetyViolation::Method(method, - MethodViolationCode::Generic) => { - err.fileline_note( - span, - &format!("method `{}` has generic type parameters", - method.name)); - } - } - } - err -} - -pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, - obligation: &PredicateObligation<'tcx>) { - // Unable to successfully determine, probably means - // insufficient type information, but could mean - // ambiguous impls. The latter *ought* to be a - // coherence violation, so we don't report it here. - - let predicate = infcx.resolve_type_vars_if_possible(&obligation.predicate); - - debug!("maybe_report_ambiguity(predicate={:?}, obligation={:?})", - predicate, - obligation); - - match predicate { - ty::Predicate::Trait(ref data) => { - let trait_ref = data.to_poly_trait_ref(); - let self_ty = trait_ref.self_ty(); - let all_types = &trait_ref.substs().types; - if all_types.references_error() { - } else { - // Typically, this ambiguity should only happen if - // there are unresolved type inference variables - // (otherwise it would suggest a coherence - // failure). But given #21974 that is not necessarily - // the case -- we can have multiple where clauses that - // are only distinguished by a region, which results - // in an ambiguity even when all types are fully - // known, since we don't dispatch based on region - // relationships. - - // This is kind of a hack: it frequently happens that some earlier - // error prevents types from being fully inferred, and then we get - // a bunch of uninteresting errors saying something like " doesn't implement Sized". It may even be true that we - // could just skip over all checks where the self-ty is an - // inference variable, but I was afraid that there might be an - // inference variable created, registered as an obligation, and - // then never forced by writeback, and hence by skipping here we'd - // be ignoring the fact that we don't KNOW the type works - // out. Though even that would probably be harmless, given that - // we're only talking about builtin traits, which are known to be - // inhabited. But in any case I just threw in this check for - // has_errors() to be sure that compilation isn't happening - // anyway. In that case, why inundate the user. - if !infcx.tcx.sess.has_errors() { - if - infcx.tcx.lang_items.sized_trait() - .map_or(false, |sized_id| sized_id == trait_ref.def_id()) - { - need_type_info(infcx, obligation.cause.span, self_ty); - } else { - let mut err = struct_span_err!(infcx.tcx.sess, obligation.cause.span, E0283, - "type annotations required: \ - cannot resolve `{}`", - predicate); - note_obligation_cause(infcx, &mut err, obligation); - err.emit(); - } - } - } - } - - ty::Predicate::WellFormed(ty) => { - // Same hacky approach as above to avoid deluging user - // with error messages. - if !ty.references_error() && !infcx.tcx.sess.has_errors() { - need_type_info(infcx, obligation.cause.span, ty); - } - } - - _ => { - if !infcx.tcx.sess.has_errors() { - let mut err = struct_span_err!(infcx.tcx.sess, obligation.cause.span, E0284, - "type annotations required: cannot resolve `{}`", - predicate); - note_obligation_cause(infcx, &mut err, obligation); - err.emit(); - } - } - } -} - -fn need_type_info<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, - span: Span, - ty: Ty<'tcx>) -{ - span_err!(infcx.tcx.sess, span, E0282, - "unable to infer enough type information about `{}`; \ - type annotations or generic parameter binding required", - ty); -} - -fn note_obligation_cause<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, - err: &mut DiagnosticBuilder, - obligation: &Obligation<'tcx, T>) - where T: fmt::Display -{ - note_obligation_cause_code(infcx, - err, - &obligation.predicate, - obligation.cause.span, - &obligation.cause.code); -} - -fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, - err: &mut DiagnosticBuilder, - predicate: &T, - cause_span: Span, - cause_code: &ObligationCauseCode<'tcx>) - where T: fmt::Display -{ - let tcx = infcx.tcx; - match *cause_code { - ObligationCauseCode::MiscObligation => { } - ObligationCauseCode::SliceOrArrayElem => { - err.fileline_note( - cause_span, - "slice and array elements must have `Sized` type"); - } - ObligationCauseCode::ProjectionWf(data) => { - err.fileline_note( - cause_span, - &format!("required so that the projection `{}` is well-formed", - data)); - } - ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => { - err.fileline_note( - cause_span, - &format!("required so that reference `{}` does not outlive its referent", - ref_ty)); - } - ObligationCauseCode::ItemObligation(item_def_id) => { - let item_name = tcx.item_path_str(item_def_id); - err.fileline_note( - cause_span, - &format!("required by `{}`", item_name)); - } - ObligationCauseCode::ObjectCastObligation(object_ty) => { - err.fileline_note( - cause_span, - &format!( - "required for the cast to the object type `{}`", - infcx.ty_to_string(object_ty))); - } - ObligationCauseCode::RepeatVec => { - err.fileline_note( - cause_span, - "the `Copy` trait is required because the \ - repeated element will be copied"); - } - ObligationCauseCode::VariableType(_) => { - err.fileline_note( - cause_span, - "all local variables must have a statically known size"); - } - ObligationCauseCode::ReturnType => { - err.fileline_note( - cause_span, - "the return type of a function must have a \ - statically known size"); - } - ObligationCauseCode::AssignmentLhsSized => { - err.fileline_note( - cause_span, - "the left-hand-side of an assignment must have a statically known size"); - } - ObligationCauseCode::StructInitializerSized => { - err.fileline_note( - cause_span, - "structs must have a statically known size to be initialized"); - } - ObligationCauseCode::ClosureCapture(var_id, _, builtin_bound) => { - let def_id = tcx.lang_items.from_builtin_kind(builtin_bound).unwrap(); - let trait_name = tcx.item_path_str(def_id); - let name = tcx.local_var_name_str(var_id); - err.fileline_note( - cause_span, - &format!("the closure that captures `{}` requires that all captured variables \ - implement the trait `{}`", - name, - trait_name)); - } - ObligationCauseCode::FieldSized => { - err.fileline_note( - cause_span, - "only the last field of a struct or enum variant \ - may have a dynamically sized type"); - } - ObligationCauseCode::SharedStatic => { - err.fileline_note( - cause_span, - "shared static variables must have a type that implements `Sync`"); - } - ObligationCauseCode::BuiltinDerivedObligation(ref data) => { - let parent_trait_ref = infcx.resolve_type_vars_if_possible(&data.parent_trait_ref); - err.fileline_note( - cause_span, - &format!("required because it appears within the type `{}`", - parent_trait_ref.0.self_ty())); - let parent_predicate = parent_trait_ref.to_predicate(); - note_obligation_cause_code(infcx, - err, - &parent_predicate, - cause_span, - &data.parent_code); - } - ObligationCauseCode::ImplDerivedObligation(ref data) => { - let parent_trait_ref = infcx.resolve_type_vars_if_possible(&data.parent_trait_ref); - err.fileline_note( - cause_span, - &format!("required because of the requirements on the impl of `{}` for `{}`", - parent_trait_ref, - parent_trait_ref.0.self_ty())); - let parent_predicate = parent_trait_ref.to_predicate(); - note_obligation_cause_code(infcx, - err, - &parent_predicate, - cause_span, - &data.parent_code); - } - ObligationCauseCode::CompareImplMethodObligation => { - err.fileline_note( - cause_span, - &format!("the requirement `{}` appears on the impl method \ - but not on the corresponding trait method", - predicate)); - } - } -} - -fn suggest_new_overflow_limit(tcx: &TyCtxt, err:&mut DiagnosticBuilder, span: Span) { - let current_limit = tcx.sess.recursion_limit.get(); - let suggested_limit = current_limit * 2; - err.fileline_note( - span, - &format!( - "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", - suggested_limit)); -} diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs deleted file mode 100644 index b2ba8a7a5f9..00000000000 --- a/src/librustc/middle/traits/fulfill.rs +++ /dev/null @@ -1,764 +0,0 @@ -// Copyright 2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use dep_graph::DepGraph; -use middle::infer::InferCtxt; -use middle::ty::{self, Ty, TyCtxt, TypeFoldable, ToPolyTraitRef}; -use rustc_data_structures::obligation_forest::{Backtrace, ObligationForest, Error}; -use std::iter; -use syntax::ast; -use util::common::ErrorReported; -use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap}; - -use super::CodeAmbiguity; -use super::CodeProjectionError; -use super::CodeSelectionError; -use super::is_object_safe; -use super::FulfillmentError; -use super::FulfillmentErrorCode; -use super::ObligationCause; -use super::PredicateObligation; -use super::project; -use super::report_overflow_error_cycle; -use super::select::SelectionContext; -use super::Unimplemented; -use super::util::predicate_for_builtin_bound; - -pub struct GlobalFulfilledPredicates<'tcx> { - set: FnvHashSet>, - dep_graph: DepGraph, -} - -#[derive(Debug)] -pub struct LocalFulfilledPredicates<'tcx> { - set: FnvHashSet> -} - -/// The fulfillment context is used to drive trait resolution. It -/// consists of a list of obligations that must be (eventually) -/// satisfied. The job is to track which are satisfied, which yielded -/// errors, and which are still pending. At any point, users can call -/// `select_where_possible`, and the fulfilment context will try to do -/// selection, retaining only those obligations that remain -/// ambiguous. This may be helpful in pushing type inference -/// along. Once all type inference constraints have been generated, the -/// method `select_all_or_error` can be used to report any remaining -/// ambiguous cases as errors. -pub struct FulfillmentContext<'tcx> { - // a simple cache that aims to cache *exact duplicate obligations* - // and avoid adding them twice. This serves a different purpose - // than the `SelectionCache`: it avoids duplicate errors and - // permits recursive obligations, which are often generated from - // traits like `Send` et al. - // - // Note that because of type inference, a predicate can still - // occur twice in the predicates list, for example when 2 - // initially-distinct type variables are unified after being - // inserted. Deduplicating the predicate set on selection had a - // significant performance cost the last time I checked. - duplicate_set: LocalFulfilledPredicates<'tcx>, - - // A list of all obligations that have been registered with this - // fulfillment context. - predicates: ObligationForest, - LocalFulfilledPredicates<'tcx>>, - - // A set of constraints that regionck must validate. Each - // constraint has the form `T:'a`, meaning "some type `T` must - // outlive the lifetime 'a". These constraints derive from - // instantiated type parameters. So if you had a struct defined - // like - // - // struct Foo { ... } - // - // then in some expression `let x = Foo { ... }` it will - // instantiate the type parameter `T` with a fresh type `$0`. At - // the same time, it will record a region obligation of - // `$0:'static`. This will get checked later by regionck. (We - // can't generally check these things right away because we have - // to wait until types are resolved.) - // - // These are stored in a map keyed to the id of the innermost - // enclosing fn body / static initializer expression. This is - // because the location where the obligation was incurred can be - // relevant with respect to which sublifetime assumptions are in - // place. The reason that we store under the fn-id, and not - // something more fine-grained, is so that it is easier for - // regionck to be sure that it has found *all* the region - // obligations (otherwise, it's easy to fail to walk to a - // particular node-id). - region_obligations: NodeMap>>, -} - -#[derive(Clone)] -pub struct RegionObligation<'tcx> { - pub sub_region: ty::Region, - pub sup_type: Ty<'tcx>, - pub cause: ObligationCause<'tcx>, -} - -#[derive(Clone, Debug)] -pub struct PendingPredicateObligation<'tcx> { - pub obligation: PredicateObligation<'tcx>, - pub stalled_on: Vec>, -} - -impl<'tcx> FulfillmentContext<'tcx> { - /// Creates a new fulfillment context. - pub fn new() -> FulfillmentContext<'tcx> { - FulfillmentContext { - duplicate_set: LocalFulfilledPredicates::new(), - predicates: ObligationForest::new(), - region_obligations: NodeMap(), - } - } - - /// "Normalize" a projection type `::X` by - /// creating a fresh type variable `$0` as well as a projection - /// predicate `::X == $0`. When the - /// inference engine runs, it will attempt to find an impl of - /// `SomeTrait` or a where clause that lets us unify `$0` with - /// something concrete. If this fails, we'll unify `$0` with - /// `projection_ty` again. - pub fn normalize_projection_type<'a>(&mut self, - infcx: &InferCtxt<'a,'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - cause: ObligationCause<'tcx>) - -> Ty<'tcx> - { - debug!("normalize_projection_type(projection_ty={:?})", - projection_ty); - - assert!(!projection_ty.has_escaping_regions()); - - // FIXME(#20304) -- cache - - let mut selcx = SelectionContext::new(infcx); - let normalized = project::normalize_projection_type(&mut selcx, projection_ty, cause, 0); - - for obligation in normalized.obligations { - self.register_predicate_obligation(infcx, obligation); - } - - debug!("normalize_projection_type: result={:?}", normalized.value); - - normalized.value - } - - pub fn register_builtin_bound<'a>(&mut self, - infcx: &InferCtxt<'a,'tcx>, - ty: Ty<'tcx>, - builtin_bound: ty::BuiltinBound, - cause: ObligationCause<'tcx>) - { - match predicate_for_builtin_bound(infcx.tcx, cause, builtin_bound, 0, ty) { - Ok(predicate) => { - self.register_predicate_obligation(infcx, predicate); - } - Err(ErrorReported) => { } - } - } - - pub fn register_region_obligation<'a>(&mut self, - t_a: Ty<'tcx>, - r_b: ty::Region, - cause: ObligationCause<'tcx>) - { - register_region_obligation(t_a, r_b, cause, &mut self.region_obligations); - } - - pub fn register_predicate_obligation<'a>(&mut self, - infcx: &InferCtxt<'a,'tcx>, - obligation: PredicateObligation<'tcx>) - { - // this helps to reduce duplicate errors, as well as making - // debug output much nicer to read and so on. - let obligation = infcx.resolve_type_vars_if_possible(&obligation); - - assert!(!obligation.has_escaping_regions()); - - if self.is_duplicate_or_add(infcx.tcx, &obligation.predicate) { - debug!("register_predicate_obligation({:?}) -- already seen, skip", obligation); - return; - } - - debug!("register_predicate_obligation({:?})", obligation); - let obligation = PendingPredicateObligation { - obligation: obligation, - stalled_on: vec![] - }; - self.predicates.push_tree(obligation, LocalFulfilledPredicates::new()); - } - - pub fn region_obligations(&self, - body_id: ast::NodeId) - -> &[RegionObligation<'tcx>] - { - match self.region_obligations.get(&body_id) { - None => Default::default(), - Some(vec) => vec, - } - } - - pub fn select_all_or_error<'a>(&mut self, - infcx: &InferCtxt<'a,'tcx>) - -> Result<(),Vec>> - { - self.select_where_possible(infcx)?; - let errors: Vec<_> = - self.predicates.to_errors(CodeAmbiguity) - .into_iter() - .map(|e| to_fulfillment_error(e)) - .collect(); - if errors.is_empty() { - Ok(()) - } else { - Err(errors) - } - } - - pub fn select_where_possible<'a>(&mut self, - infcx: &InferCtxt<'a,'tcx>) - -> Result<(),Vec>> - { - let mut selcx = SelectionContext::new(infcx); - self.select(&mut selcx) - } - - pub fn pending_obligations(&self) -> Vec> { - self.predicates.pending_obligations() - } - - fn is_duplicate_or_add(&mut self, - tcx: &TyCtxt<'tcx>, - predicate: &ty::Predicate<'tcx>) - -> bool { - // For "global" predicates -- that is, predicates that don't - // involve type parameters, inference variables, or regions - // other than 'static -- we can check the cache in the tcx, - // which allows us to leverage work from other threads. Note - // that we don't add anything to this cache yet (unlike the - // local cache). This is because the tcx cache maintains the - // invariant that it only contains things that have been - // proven, and we have not yet proven that `predicate` holds. - if tcx.fulfilled_predicates.borrow().check_duplicate(predicate) { - return true; - } - - // If `predicate` is not global, or not present in the tcx - // cache, we can still check for it in our local cache and add - // it if not present. Note that if we find this predicate in - // the local cache we can stop immediately, without reporting - // any errors, even though we don't know yet if it is - // true. This is because, while we don't yet know if the - // predicate holds, we know that this same fulfillment context - // already is in the process of finding out. - self.duplicate_set.is_duplicate_or_add(predicate) - } - - /// Attempts to select obligations using `selcx`. If `only_new_obligations` is true, then it - /// only attempts to select obligations that haven't been seen before. - fn select<'a>(&mut self, - selcx: &mut SelectionContext<'a, 'tcx>) - -> Result<(),Vec>> - { - debug!("select(obligation-forest-size={})", self.predicates.len()); - - let mut errors = Vec::new(); - - loop { - debug!("select: starting another iteration"); - - // Process pending obligations. - let outcome = { - let region_obligations = &mut self.region_obligations; - self.predicates.process_obligations( - |obligation, tree, backtrace| process_predicate(selcx, - tree, - obligation, - backtrace, - region_obligations)) - }; - - debug!("select: outcome={:?}", outcome); - - // these are obligations that were proven to be true. - for pending_obligation in outcome.completed { - let predicate = &pending_obligation.obligation.predicate; - selcx.tcx().fulfilled_predicates.borrow_mut().add_if_global(predicate); - } - - errors.extend( - outcome.errors.into_iter() - .map(|e| to_fulfillment_error(e))); - - // If nothing new was added, no need to keep looping. - if outcome.stalled { - break; - } - } - - debug!("select({} predicates remaining, {} errors) done", - self.predicates.len(), errors.len()); - - if errors.is_empty() { - Ok(()) - } else { - Err(errors) - } - } -} - -/// Like `process_predicate1`, but wrap result into a pending predicate. -fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, - tree_cache: &mut LocalFulfilledPredicates<'tcx>, - pending_obligation: &mut PendingPredicateObligation<'tcx>, - mut backtrace: Backtrace>, - region_obligations: &mut NodeMap>>) - -> Result>>, - FulfillmentErrorCode<'tcx>> -{ - match process_predicate1(selcx, pending_obligation, backtrace.clone(), region_obligations) { - Ok(Some(v)) => { - // FIXME(#30977) The code below is designed to detect (and - // permit) DAGs, while still ensuring that the reasoning - // is acyclic. However, it does a few things - // suboptimally. For example, it refreshes type variables - // a lot, probably more than needed, but also less than - // you might want. - // - // - more than needed: I want to be very sure we don't - // accidentally treat a cycle as a DAG, so I am - // refreshing type variables as we walk the ancestors; - // but we are going to repeat this a lot, which is - // sort of silly, and it would be nicer to refresh - // them *in place* so that later predicate processing - // can benefit from the same work; - // - less than you might want: we only add items in the cache here, - // but maybe we learn more about type variables and could add them into - // the cache later on. - - let tcx = selcx.tcx(); - - // Compute a little FnvHashSet for the ancestors. We only - // do this the first time that we care. - let mut cache = None; - let mut is_ancestor = |predicate: &ty::Predicate<'tcx>| { - if cache.is_none() { - let mut c = FnvHashSet(); - for ancestor in backtrace.by_ref() { - // Ugh. This just feels ridiculously - // inefficient. But we need to compare - // predicates without being concerned about - // the vagaries of type inference, so for now - // just ensure that they are always - // up-to-date. (I suppose we could just use a - // snapshot and check if they are unifiable?) - let resolved_predicate = - selcx.infcx().resolve_type_vars_if_possible( - &ancestor.obligation.predicate); - c.insert(resolved_predicate); - } - cache = Some(c); - } - - cache.as_ref().unwrap().contains(predicate) - }; - - let pending_predicate_obligations: Vec<_> = - v.into_iter() - .filter_map(|obligation| { - // Probably silly, but remove any inference - // variables. This is actually crucial to the - // ancestor check below, but it's not clear that - // it makes sense to ALWAYS do it. - let obligation = selcx.infcx().resolve_type_vars_if_possible(&obligation); - - // Screen out obligations that we know globally - // are true. This should really be the DAG check - // mentioned above. - if tcx.fulfilled_predicates.borrow().check_duplicate(&obligation.predicate) { - return None; - } - - // Check whether this obligation appears somewhere else in the tree. - if tree_cache.is_duplicate_or_add(&obligation.predicate) { - // If the obligation appears as a parent, - // allow it, because that is a cycle. - // Otherwise though we can just ignore - // it. Note that we have to be careful around - // inference variables here -- for the - // purposes of the ancestor check, we retain - // the invariant that all type variables are - // fully refreshed. - if !is_ancestor(&obligation.predicate) { - return None; - } - } - - Some(PendingPredicateObligation { - obligation: obligation, - stalled_on: vec![] - }) - }) - .collect(); - - Ok(Some(pending_predicate_obligations)) - } - Ok(None) => Ok(None), - Err(e) => Err(e) - } -} - - -/// Return the set of type variables contained in a trait ref -fn trait_ref_type_vars<'a, 'tcx>(selcx: &mut SelectionContext<'a, 'tcx>, - t: ty::PolyTraitRef<'tcx>) -> Vec> -{ - t.skip_binder() // ok b/c this check doesn't care about regions - .input_types() - .iter() - .map(|t| selcx.infcx().resolve_type_vars_if_possible(t)) - .filter(|t| t.has_infer_types()) - .flat_map(|t| t.walk()) - .filter(|t| match t.sty { ty::TyInfer(_) => true, _ => false }) - .collect() -} - -/// Processes a predicate obligation and returns either: -/// - `Ok(Some(v))` if the predicate is true, presuming that `v` are also true -/// - `Ok(None)` if we don't have enough info to be sure -/// - `Err` if the predicate does not hold -fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, - pending_obligation: &mut PendingPredicateObligation<'tcx>, - backtrace: Backtrace>, - region_obligations: &mut NodeMap>>) - -> Result>>, - FulfillmentErrorCode<'tcx>> -{ - // if we were stalled on some unresolved variables, first check - // whether any of them have been resolved; if not, don't bother - // doing more work yet - if !pending_obligation.stalled_on.is_empty() { - if pending_obligation.stalled_on.iter().all(|&ty| { - let resolved_ty = selcx.infcx().shallow_resolve(&ty); - resolved_ty == ty // nothing changed here - }) { - debug!("process_predicate: pending obligation {:?} still stalled on {:?}", - selcx.infcx().resolve_type_vars_if_possible(&pending_obligation.obligation), - pending_obligation.stalled_on); - return Ok(None); - } - pending_obligation.stalled_on = vec![]; - } - - let obligation = &mut pending_obligation.obligation; - - // If we exceed the recursion limit, take a moment to look for a - // cycle so we can give a better error report from here, where we - // have more context. - let recursion_limit = selcx.tcx().sess.recursion_limit.get(); - if obligation.recursion_depth >= recursion_limit { - if let Some(cycle) = scan_for_cycle(obligation, &backtrace) { - report_overflow_error_cycle(selcx.infcx(), &cycle); - } - } - - if obligation.predicate.has_infer_types() { - obligation.predicate = selcx.infcx().resolve_type_vars_if_possible(&obligation.predicate); - } - - match obligation.predicate { - ty::Predicate::Trait(ref data) => { - if selcx.tcx().fulfilled_predicates.borrow().check_duplicate_trait(data) { - return Ok(Some(vec![])); - } - - if coinductive_match(selcx, obligation, data, &backtrace) { - return Ok(Some(vec![])); - } - - let trait_obligation = obligation.with(data.clone()); - match selcx.select(&trait_obligation) { - Ok(Some(vtable)) => { - info!("selecting trait `{:?}` at depth {} yielded Ok(Some)", - data, obligation.recursion_depth); - Ok(Some(vtable.nested_obligations())) - } - Ok(None) => { - info!("selecting trait `{:?}` at depth {} yielded Ok(None)", - data, obligation.recursion_depth); - - // This is a bit subtle: for the most part, the - // only reason we can fail to make progress on - // trait selection is because we don't have enough - // information about the types in the trait. One - // exception is that we sometimes haven't decided - // what kind of closure a closure is. *But*, in - // that case, it turns out, the type of the - // closure will also change, because the closure - // also includes references to its upvars as part - // of its type, and those types are resolved at - // the same time. - pending_obligation.stalled_on = - trait_ref_type_vars(selcx, data.to_poly_trait_ref()); - - debug!("process_predicate: pending obligation {:?} now stalled on {:?}", - selcx.infcx().resolve_type_vars_if_possible(obligation), - pending_obligation.stalled_on); - - Ok(None) - } - Err(selection_err) => { - info!("selecting trait `{:?}` at depth {} yielded Err", - data, obligation.recursion_depth); - Err(CodeSelectionError(selection_err)) - } - } - } - - ty::Predicate::Equate(ref binder) => { - match selcx.infcx().equality_predicate(obligation.cause.span, binder) { - Ok(()) => Ok(Some(Vec::new())), - Err(_) => Err(CodeSelectionError(Unimplemented)), - } - } - - ty::Predicate::RegionOutlives(ref binder) => { - match selcx.infcx().region_outlives_predicate(obligation.cause.span, binder) { - Ok(()) => Ok(Some(Vec::new())), - Err(_) => Err(CodeSelectionError(Unimplemented)), - } - } - - ty::Predicate::TypeOutlives(ref binder) => { - // Check if there are higher-ranked regions. - match selcx.tcx().no_late_bound_regions(binder) { - // If there are, inspect the underlying type further. - None => { - // Convert from `Binder>` to `Binder`. - let binder = binder.map_bound_ref(|pred| pred.0); - - // Check if the type has any bound regions. - match selcx.tcx().no_late_bound_regions(&binder) { - // If so, this obligation is an error (for now). Eventually we should be - // able to support additional cases here, like `for<'a> &'a str: 'a`. - None => { - Err(CodeSelectionError(Unimplemented)) - } - // Otherwise, we have something of the form - // `for<'a> T: 'a where 'a not in T`, which we can treat as `T: 'static`. - Some(t_a) => { - register_region_obligation(t_a, ty::ReStatic, - obligation.cause.clone(), - region_obligations); - Ok(Some(vec![])) - } - } - } - // If there aren't, register the obligation. - Some(ty::OutlivesPredicate(t_a, r_b)) => { - register_region_obligation(t_a, r_b, - obligation.cause.clone(), - region_obligations); - Ok(Some(vec![])) - } - } - } - - ty::Predicate::Projection(ref data) => { - let project_obligation = obligation.with(data.clone()); - match project::poly_project_and_unify_type(selcx, &project_obligation) { - Ok(None) => { - pending_obligation.stalled_on = - trait_ref_type_vars(selcx, data.to_poly_trait_ref()); - Ok(None) - } - Ok(v) => Ok(v), - Err(e) => Err(CodeProjectionError(e)) - } - } - - ty::Predicate::ObjectSafe(trait_def_id) => { - if !is_object_safe(selcx.tcx(), trait_def_id) { - Err(CodeSelectionError(Unimplemented)) - } else { - Ok(Some(Vec::new())) - } - } - - ty::Predicate::WellFormed(ty) => { - match ty::wf::obligations(selcx.infcx(), obligation.cause.body_id, - ty, obligation.cause.span) { - None => { - pending_obligation.stalled_on = vec![ty]; - Ok(None) - } - s => Ok(s) - } - } - } -} - -/// For defaulted traits, we use a co-inductive strategy to solve, so -/// that recursion is ok. This routine returns true if the top of the -/// stack (`top_obligation` and `top_data`): -/// - is a defaulted trait, and -/// - it also appears in the backtrace at some position `X`; and, -/// - all the predicates at positions `X..` between `X` an the top are -/// also defaulted traits. -fn coinductive_match<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, - top_obligation: &PredicateObligation<'tcx>, - top_data: &ty::PolyTraitPredicate<'tcx>, - backtrace: &Backtrace>) - -> bool -{ - if selcx.tcx().trait_has_default_impl(top_data.def_id()) { - debug!("coinductive_match: top_data={:?}", top_data); - for bt_obligation in backtrace.clone() { - debug!("coinductive_match: bt_obligation={:?}", bt_obligation); - - // *Everything* in the backtrace must be a defaulted trait. - match bt_obligation.obligation.predicate { - ty::Predicate::Trait(ref data) => { - if !selcx.tcx().trait_has_default_impl(data.def_id()) { - debug!("coinductive_match: trait does not have default impl"); - break; - } - } - _ => { break; } - } - - // And we must find a recursive match. - if bt_obligation.obligation.predicate == top_obligation.predicate { - debug!("coinductive_match: found a match in the backtrace"); - return true; - } - } - } - - false -} - -fn scan_for_cycle<'a,'tcx>(top_obligation: &PredicateObligation<'tcx>, - backtrace: &Backtrace>) - -> Option>> -{ - let mut map = FnvHashMap(); - let all_obligations = - || iter::once(top_obligation) - .chain(backtrace.clone() - .map(|p| &p.obligation)); - for (index, bt_obligation) in all_obligations().enumerate() { - if let Some(&start) = map.get(&bt_obligation.predicate) { - // Found a cycle starting at position `start` and running - // until the current position (`index`). - return Some(all_obligations().skip(start).take(index - start + 1).cloned().collect()); - } else { - map.insert(bt_obligation.predicate.clone(), index); - } - } - None -} - -fn register_region_obligation<'tcx>(t_a: Ty<'tcx>, - r_b: ty::Region, - cause: ObligationCause<'tcx>, - region_obligations: &mut NodeMap>>) -{ - let region_obligation = RegionObligation { sup_type: t_a, - sub_region: r_b, - cause: cause }; - - debug!("register_region_obligation({:?}, cause={:?})", - region_obligation, region_obligation.cause); - - region_obligations.entry(region_obligation.cause.body_id) - .or_insert(vec![]) - .push(region_obligation); - -} - -impl<'tcx> LocalFulfilledPredicates<'tcx> { - pub fn new() -> LocalFulfilledPredicates<'tcx> { - LocalFulfilledPredicates { - set: FnvHashSet() - } - } - - fn is_duplicate_or_add(&mut self, key: &ty::Predicate<'tcx>) -> bool { - // For a `LocalFulfilledPredicates`, if we find a match, we - // don't need to add a read edge to the dep-graph. This is - // because it means that the predicate has already been - // considered by this `FulfillmentContext`, and hence the - // containing task will already have an edge. (Here we are - // assuming each `FulfillmentContext` only gets used from one - // task; but to do otherwise makes no sense) - !self.set.insert(key.clone()) - } -} - -impl<'tcx> GlobalFulfilledPredicates<'tcx> { - pub fn new(dep_graph: DepGraph) -> GlobalFulfilledPredicates<'tcx> { - GlobalFulfilledPredicates { - set: FnvHashSet(), - dep_graph: dep_graph, - } - } - - pub fn check_duplicate(&self, key: &ty::Predicate<'tcx>) -> bool { - if let ty::Predicate::Trait(ref data) = *key { - self.check_duplicate_trait(data) - } else { - false - } - } - - pub fn check_duplicate_trait(&self, data: &ty::PolyTraitPredicate<'tcx>) -> bool { - // For the global predicate registry, when we find a match, it - // may have been computed by some other task, so we want to - // add a read from the node corresponding to the predicate - // processing to make sure we get the transitive dependencies. - if self.set.contains(data) { - debug_assert!(data.is_global()); - self.dep_graph.read(data.dep_node()); - debug!("check_duplicate: global predicate `{:?}` already proved elsewhere", data); - - info!("check_duplicate_trait hit: `{:?}`", data); - - true - } else { - false - } - } - - fn add_if_global(&mut self, key: &ty::Predicate<'tcx>) { - if let ty::Predicate::Trait(ref data) = *key { - // We only add things to the global predicate registry - // after the current task has proved them, and hence - // already has the required read edges, so we don't need - // to add any more edges here. - if data.is_global() { - if self.set.insert(data.clone()) { - debug!("add_if_global: global predicate `{:?}` added", data); - info!("check_duplicate_trait entry: `{:?}`", data); - } - } - } - } -} - -fn to_fulfillment_error<'tcx>( - error: Error, FulfillmentErrorCode<'tcx>>) - -> FulfillmentError<'tcx> -{ - let obligation = error.backtrace.into_iter().next().unwrap().obligation; - FulfillmentError::new(obligation, error.error) -} diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs deleted file mode 100644 index 94047318599..00000000000 --- a/src/librustc/middle/traits/mod.rs +++ /dev/null @@ -1,623 +0,0 @@ -// Copyright 2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Trait Resolution. See the Book for more. - -pub use self::SelectionError::*; -pub use self::FulfillmentErrorCode::*; -pub use self::Vtable::*; -pub use self::ObligationCauseCode::*; - -use middle::def_id::DefId; -use middle::free_region::FreeRegionMap; -use middle::ty::subst; -use middle::ty::{self, Ty, TypeFoldable}; -use middle::infer::{self, fixup_err_to_string, InferCtxt}; - -use std::rc::Rc; -use syntax::ast; -use syntax::codemap::{Span, DUMMY_SP}; - -pub use self::error_reporting::TraitErrorKey; -pub use self::error_reporting::recursive_type_with_infinite_size_error; -pub use self::error_reporting::report_fulfillment_errors; -pub use self::error_reporting::report_overflow_error; -pub use self::error_reporting::report_overflow_error_cycle; -pub use self::error_reporting::report_selection_error; -pub use self::error_reporting::report_object_safety_error; -pub use self::coherence::orphan_check; -pub use self::coherence::overlapping_impls; -pub use self::coherence::OrphanCheckErr; -pub use self::fulfill::{FulfillmentContext, GlobalFulfilledPredicates, RegionObligation}; -pub use self::project::{MismatchedProjectionTypes, ProjectionMode}; -pub use self::project::{normalize, Normalized}; -pub use self::object_safety::is_object_safe; -pub use self::object_safety::astconv_object_safety_violations; -pub use self::object_safety::object_safety_violations; -pub use self::object_safety::ObjectSafetyViolation; -pub use self::object_safety::MethodViolationCode; -pub use self::object_safety::is_vtable_safe_method; -pub use self::select::{EvaluationCache, SelectionContext, SelectionCache}; -pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch}; -pub use self::select::{MethodMatchedData}; // intentionally don't export variants -pub use self::specialize::{Overlap, specialization_graph, specializes, translate_substs}; -pub use self::util::elaborate_predicates; -pub use self::util::get_vtable_index_of_object_method; -pub use self::util::trait_ref_for_builtin_bound; -pub use self::util::predicate_for_trait_def; -pub use self::util::supertraits; -pub use self::util::Supertraits; -pub use self::util::supertrait_def_ids; -pub use self::util::SupertraitDefIds; -pub use self::util::transitive_bounds; -pub use self::util::upcast; - -mod coherence; -mod error_reporting; -mod fulfill; -mod project; -mod object_safety; -mod select; -mod specialize; -mod structural_impls; -mod util; - -/// An `Obligation` represents some trait reference (e.g. `int:Eq`) for -/// which the vtable must be found. The process of finding a vtable is -/// called "resolving" the `Obligation`. This process consists of -/// either identifying an `impl` (e.g., `impl Eq for int`) that -/// provides the required vtable, or else finding a bound that is in -/// scope. The eventual result is usually a `Selection` (defined below). -#[derive(Clone, PartialEq, Eq)] -pub struct Obligation<'tcx, T> { - pub cause: ObligationCause<'tcx>, - pub recursion_depth: usize, - pub predicate: T, -} - -pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>; -pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; - -/// Why did we incur this obligation? Used for error reporting. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct ObligationCause<'tcx> { - pub span: Span, - - // The id of the fn body that triggered this obligation. This is - // used for region obligations to determine the precise - // environment in which the region obligation should be evaluated - // (in particular, closures can add new assumptions). See the - // field `region_obligations` of the `FulfillmentContext` for more - // information. - pub body_id: ast::NodeId, - - pub code: ObligationCauseCode<'tcx> -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum ObligationCauseCode<'tcx> { - /// Not well classified or should be obvious from span. - MiscObligation, - - /// This is the trait reference from the given projection - SliceOrArrayElem, - - /// This is the trait reference from the given projection - ProjectionWf(ty::ProjectionTy<'tcx>), - - /// In an impl of trait X for type Y, type Y must - /// also implement all supertraits of X. - ItemObligation(DefId), - - /// A type like `&'a T` is WF only if `T: 'a`. - ReferenceOutlivesReferent(Ty<'tcx>), - - /// Obligation incurred due to an object cast. - ObjectCastObligation(/* Object type */ Ty<'tcx>), - - /// Various cases where expressions must be sized/copy/etc: - AssignmentLhsSized, // L = X implies that L is Sized - StructInitializerSized, // S { ... } must be Sized - VariableType(ast::NodeId), // Type of each variable must be Sized - ReturnType, // Return type must be Sized - RepeatVec, // [T,..n] --> T must be Copy - - // Captures of variable the given id by a closure (span is the - // span of the closure) - ClosureCapture(ast::NodeId, Span, ty::BuiltinBound), - - // Types of fields (other than the last) in a struct must be sized. - FieldSized, - - // static items must have `Sync` type - SharedStatic, - - BuiltinDerivedObligation(DerivedObligationCause<'tcx>), - - ImplDerivedObligation(DerivedObligationCause<'tcx>), - - CompareImplMethodObligation, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct DerivedObligationCause<'tcx> { - /// The trait reference of the parent obligation that led to the - /// current obligation. Note that only trait obligations lead to - /// derived obligations, so we just store the trait reference here - /// directly. - parent_trait_ref: ty::PolyTraitRef<'tcx>, - - /// The parent trait had this cause - parent_code: Rc> -} - -pub type Obligations<'tcx, O> = Vec>; -pub type PredicateObligations<'tcx> = Vec>; -pub type TraitObligations<'tcx> = Vec>; - -pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>; - -#[derive(Clone,Debug)] -pub enum SelectionError<'tcx> { - Unimplemented, - OutputTypeParameterMismatch(ty::PolyTraitRef<'tcx>, - ty::PolyTraitRef<'tcx>, - ty::error::TypeError<'tcx>), - TraitNotObjectSafe(DefId), -} - -pub struct FulfillmentError<'tcx> { - pub obligation: PredicateObligation<'tcx>, - pub code: FulfillmentErrorCode<'tcx> -} - -#[derive(Clone)] -pub enum FulfillmentErrorCode<'tcx> { - CodeSelectionError(SelectionError<'tcx>), - CodeProjectionError(MismatchedProjectionTypes<'tcx>), - CodeAmbiguity, -} - -/// When performing resolution, it is typically the case that there -/// can be one of three outcomes: -/// -/// - `Ok(Some(r))`: success occurred with result `r` -/// - `Ok(None)`: could not definitely determine anything, usually due -/// to inconclusive type inference. -/// - `Err(e)`: error `e` occurred -pub type SelectionResult<'tcx, T> = Result, SelectionError<'tcx>>; - -/// Given the successful resolution of an obligation, the `Vtable` -/// indicates where the vtable comes from. Note that while we call this -/// a "vtable", it does not necessarily indicate dynamic dispatch at -/// runtime. `Vtable` instances just tell the compiler where to find -/// methods, but in generic code those methods are typically statically -/// dispatched -- only when an object is constructed is a `Vtable` -/// instance reified into an actual vtable. -/// -/// For example, the vtable may be tied to a specific impl (case A), -/// or it may be relative to some bound that is in scope (case B). -/// -/// -/// ``` -/// impl Clone for Option { ... } // Impl_1 -/// impl Clone for Box { ... } // Impl_2 -/// impl Clone for int { ... } // Impl_3 -/// -/// fn foo(concrete: Option>, -/// param: T, -/// mixed: Option) { -/// -/// // Case A: Vtable points at a specific impl. Only possible when -/// // type is concretely known. If the impl itself has bounded -/// // type parameters, Vtable will carry resolutions for those as well: -/// concrete.clone(); // Vtable(Impl_1, [Vtable(Impl_2, [Vtable(Impl_3)])]) -/// -/// // Case B: Vtable must be provided by caller. This applies when -/// // type is a type parameter. -/// param.clone(); // VtableParam -/// -/// // Case C: A mix of cases A and B. -/// mixed.clone(); // Vtable(Impl_1, [VtableParam]) -/// } -/// ``` -/// -/// ### The type parameter `N` -/// -/// See explanation on `VtableImplData`. -#[derive(Clone)] -pub enum Vtable<'tcx, N> { - /// Vtable identifying a particular impl. - VtableImpl(VtableImplData<'tcx, N>), - - /// Vtable for default trait implementations - /// This carries the information and nested obligations with regards - /// to a default implementation for a trait `Trait`. The nested obligations - /// ensure the trait implementation holds for all the constituent types. - VtableDefaultImpl(VtableDefaultImplData), - - /// Successful resolution to an obligation provided by the caller - /// for some type parameter. The `Vec` represents the - /// obligations incurred from normalizing the where-clause (if - /// any). - VtableParam(Vec), - - /// Virtual calls through an object - VtableObject(VtableObjectData<'tcx>), - - /// Successful resolution for a builtin trait. - VtableBuiltin(VtableBuiltinData), - - /// Vtable automatically generated for a closure. The def ID is the ID - /// of the closure expression. This is a `VtableImpl` in spirit, but the - /// impl is generated by the compiler and does not appear in the source. - VtableClosure(VtableClosureData<'tcx, N>), - - /// Same as above, but for a fn pointer type with the given signature. - VtableFnPointer(ty::Ty<'tcx>), -} - -/// Identifies a particular impl in the source, along with a set of -/// substitutions from the impl's type/lifetime parameters. The -/// `nested` vector corresponds to the nested obligations attached to -/// the impl's type parameters. -/// -/// The type parameter `N` indicates the type used for "nested -/// obligations" that are required by the impl. During type check, this -/// is `Obligation`, as one might expect. During trans, however, this -/// is `()`, because trans only requires a shallow resolution of an -/// impl, and nested obligations are satisfied later. -#[derive(Clone, PartialEq, Eq)] -pub struct VtableImplData<'tcx, N> { - pub impl_def_id: DefId, - pub substs: &'tcx subst::Substs<'tcx>, - pub nested: Vec -} - -#[derive(Clone, PartialEq, Eq)] -pub struct VtableClosureData<'tcx, N> { - pub closure_def_id: DefId, - pub substs: ty::ClosureSubsts<'tcx>, - /// Nested obligations. This can be non-empty if the closure - /// signature contains associated types. - pub nested: Vec -} - -#[derive(Clone)] -pub struct VtableDefaultImplData { - pub trait_def_id: DefId, - pub nested: Vec -} - -#[derive(Clone)] -pub struct VtableBuiltinData { - pub nested: Vec -} - -/// A vtable for some object-safe trait `Foo` automatically derived -/// for the object type `Foo`. -#[derive(PartialEq,Eq,Clone)] -pub struct VtableObjectData<'tcx> { - /// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`. - pub upcast_trait_ref: ty::PolyTraitRef<'tcx>, - - /// The vtable is formed by concatenating together the method lists of - /// the base object trait and all supertraits; this is the start of - /// `upcast_trait_ref`'s methods in that vtable. - pub vtable_base: usize -} - -/// Creates predicate obligations from the generic bounds. -pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>, - generic_bounds: &ty::InstantiatedPredicates<'tcx>) - -> PredicateObligations<'tcx> -{ - util::predicates_for_generics(cause, 0, generic_bounds) -} - -/// Determines whether the type `ty` is known to meet `bound` and -/// returns true if so. Returns false if `ty` either does not meet -/// `bound` or is not known to meet bound (note that this is -/// conservative towards *no impl*, which is the opposite of the -/// `evaluate` methods). -pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, - ty: Ty<'tcx>, - bound: ty::BuiltinBound, - span: Span) - -> bool -{ - debug!("type_known_to_meet_builtin_bound(ty={:?}, bound={:?})", - ty, - bound); - - let cause = ObligationCause::misc(span, ast::DUMMY_NODE_ID); - let obligation = - util::predicate_for_builtin_bound(infcx.tcx, cause, bound, 0, ty); - let obligation = match obligation { - Ok(o) => o, - Err(..) => return false - }; - let result = SelectionContext::new(infcx) - .evaluate_obligation_conservatively(&obligation); - debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} => {:?}", - ty, bound, result); - - if result && (ty.has_infer_types() || ty.has_closure_types()) { - // Because of inference "guessing", selection can sometimes claim - // to succeed while the success requires a guess. To ensure - // this function's result remains infallible, we must confirm - // that guess. While imperfect, I believe this is sound. - - let mut fulfill_cx = FulfillmentContext::new(); - - // We can use a dummy node-id here because we won't pay any mind - // to region obligations that arise (there shouldn't really be any - // anyhow). - let cause = ObligationCause::misc(span, ast::DUMMY_NODE_ID); - - fulfill_cx.register_builtin_bound(infcx, ty, bound, cause); - - // Note: we only assume something is `Copy` if we can - // *definitively* show that it implements `Copy`. Otherwise, - // assume it is move; linear is always ok. - match fulfill_cx.select_all_or_error(infcx) { - Ok(()) => { - debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} success", - ty, - bound); - true - } - Err(e) => { - debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} errors={:?}", - ty, - bound, - e); - false - } - } - } else { - result - } -} - -// FIXME: this is gonna need to be removed ... -/// Normalizes the parameter environment, reporting errors if they occur. -pub fn normalize_param_env_or_error<'a,'tcx>(unnormalized_env: ty::ParameterEnvironment<'a,'tcx>, - cause: ObligationCause<'tcx>) - -> ty::ParameterEnvironment<'a,'tcx> -{ - // I'm not wild about reporting errors here; I'd prefer to - // have the errors get reported at a defined place (e.g., - // during typeck). Instead I have all parameter - // environments, in effect, going through this function - // and hence potentially reporting errors. This ensurse of - // course that we never forget to normalize (the - // alternative seemed like it would involve a lot of - // manual invocations of this fn -- and then we'd have to - // deal with the errors at each of those sites). - // - // In any case, in practice, typeck constructs all the - // parameter environments once for every fn as it goes, - // and errors will get reported then; so after typeck we - // can be sure that no errors should occur. - - let tcx = unnormalized_env.tcx; - let span = cause.span; - let body_id = cause.body_id; - - debug!("normalize_param_env_or_error(unnormalized_env={:?})", - unnormalized_env); - - let predicates: Vec<_> = - util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.clone()) - .filter(|p| !p.is_global()) // (*) - .collect(); - - // (*) Any predicate like `i32: Trait` or whatever doesn't - // need to be in the *environment* to be proven, so screen those - // out. This is important for the soundness of inter-fn - // caching. Note though that we should probably check that these - // predicates hold at the point where the environment is - // constructed, but I am not currently doing so out of laziness. - // -nmatsakis - - debug!("normalize_param_env_or_error: elaborated-predicates={:?}", - predicates); - - let elaborated_env = unnormalized_env.with_caller_bounds(predicates); - - let infcx = infer::new_infer_ctxt(tcx, - &tcx.tables, - Some(elaborated_env), - ProjectionMode::AnyFinal); - let predicates = match fully_normalize(&infcx, - cause, - &infcx.parameter_environment.caller_bounds) { - Ok(predicates) => predicates, - Err(errors) => { - report_fulfillment_errors(&infcx, &errors); - return infcx.parameter_environment; // an unnormalized env is better than nothing - } - }; - - debug!("normalize_param_env_or_error: normalized predicates={:?}", - predicates); - - let free_regions = FreeRegionMap::new(); - infcx.resolve_regions_and_report_errors(&free_regions, body_id); - let predicates = match infcx.fully_resolve(&predicates) { - Ok(predicates) => predicates, - Err(fixup_err) => { - // If we encounter a fixup error, it means that some type - // variable wound up unconstrained. I actually don't know - // if this can happen, and I certainly don't expect it to - // happen often, but if it did happen it probably - // represents a legitimate failure due to some kind of - // unconstrained variable, and it seems better not to ICE, - // all things considered. - let err_msg = fixup_err_to_string(fixup_err); - tcx.sess.span_err(span, &err_msg); - return infcx.parameter_environment; // an unnormalized env is better than nothing - } - }; - - debug!("normalize_param_env_or_error: resolved predicates={:?}", - predicates); - - infcx.parameter_environment.with_caller_bounds(predicates) -} - -pub fn fully_normalize<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, - cause: ObligationCause<'tcx>, - value: &T) - -> Result>> - where T : TypeFoldable<'tcx> -{ - debug!("fully_normalize(value={:?})", value); - - let mut selcx = &mut SelectionContext::new(infcx); - // FIXME (@jroesch) ISSUE 26721 - // I'm not sure if this is a bug or not, needs further investigation. - // It appears that by reusing the fulfillment_cx here we incur more - // obligations and later trip an asssertion on regionck.rs line 337. - // - // The two possibilities I see is: - // - normalization is not actually fully happening and we - // have a bug else where - // - we are adding a duplicate bound into the list causing - // its size to change. - // - // I think we should probably land this refactor and then come - // back to this is a follow-up patch. - let mut fulfill_cx = FulfillmentContext::new(); - - let Normalized { value: normalized_value, obligations } = - project::normalize(selcx, cause, value); - debug!("fully_normalize: normalized_value={:?} obligations={:?}", - normalized_value, - obligations); - for obligation in obligations { - fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation); - } - - debug!("fully_normalize: select_all_or_error start"); - match fulfill_cx.select_all_or_error(infcx) { - Ok(()) => { } - Err(e) => { - debug!("fully_normalize: error={:?}", e); - return Err(e); - } - } - debug!("fully_normalize: select_all_or_error complete"); - let resolved_value = infcx.resolve_type_vars_if_possible(&normalized_value); - debug!("fully_normalize: resolved_value={:?}", resolved_value); - Ok(resolved_value) -} - -impl<'tcx,O> Obligation<'tcx,O> { - pub fn new(cause: ObligationCause<'tcx>, - trait_ref: O) - -> Obligation<'tcx, O> - { - Obligation { cause: cause, - recursion_depth: 0, - predicate: trait_ref } - } - - fn with_depth(cause: ObligationCause<'tcx>, - recursion_depth: usize, - trait_ref: O) - -> Obligation<'tcx, O> - { - Obligation { cause: cause, - recursion_depth: recursion_depth, - predicate: trait_ref } - } - - pub fn misc(span: Span, body_id: ast::NodeId, trait_ref: O) -> Obligation<'tcx, O> { - Obligation::new(ObligationCause::misc(span, body_id), trait_ref) - } - - pub fn with

(&self, mut pred: P) -> bool where - P: FnMut(&[T]) -> bool, - { - let spaces = [TypeSpace, SelfSpace, FnSpace]; - spaces.iter().all(|&space| { pred(self.get_slice(space)) }) - } - - pub fn all

(&self, pred: P) -> bool where P: FnMut(&T) -> bool { - self.iter().all(pred) - } - - pub fn any

(&self, pred: P) -> bool where P: FnMut(&T) -> bool { - self.iter().any(pred) - } - - pub fn is_empty(&self) -> bool { - self.all_vecs(|v| v.is_empty()) - } - - pub fn map(&self, pred: P) -> VecPerParamSpace where P: FnMut(&T) -> U { - let result = self.iter().map(pred).collect(); - VecPerParamSpace::new_internal(result, - self.type_limit, - self.self_limit) - } - - pub fn map_enumerated(&self, pred: P) -> VecPerParamSpace where - P: FnMut((ParamSpace, usize, &T)) -> U, - { - let result = self.iter_enumerated().map(pred).collect(); - VecPerParamSpace::new_internal(result, - self.type_limit, - self.self_limit) - } - - pub fn split(self) -> SeparateVecsPerParamSpace { - let VecPerParamSpace { type_limit, self_limit, content } = self; - - let mut content_iter = content.into_iter(); - - SeparateVecsPerParamSpace { - types: content_iter.by_ref().take(type_limit).collect(), - selfs: content_iter.by_ref().take(self_limit - type_limit).collect(), - fns: content_iter.collect() - } - } - - pub fn with_slice(mut self, space: ParamSpace, slice: &[T]) - -> VecPerParamSpace - where T: Clone - { - assert!(self.is_empty_in(space)); - for t in slice { - self.push(space, t.clone()); - } - - self - } -} - -#[derive(Clone)] -pub struct EnumeratedItems<'a,T:'a> { - vec: &'a VecPerParamSpace, - space_index: usize, - elem_index: usize -} - -impl<'a,T> EnumeratedItems<'a,T> { - fn new(v: &'a VecPerParamSpace) -> EnumeratedItems<'a,T> { - let mut result = EnumeratedItems { vec: v, space_index: 0, elem_index: 0 }; - result.adjust_space(); - result - } - - fn adjust_space(&mut self) { - let spaces = ParamSpace::all(); - while - self.space_index < spaces.len() && - self.elem_index >= self.vec.len(spaces[self.space_index]) - { - self.space_index += 1; - self.elem_index = 0; - } - } -} - -impl<'a,T> Iterator for EnumeratedItems<'a,T> { - type Item = (ParamSpace, usize, &'a T); - - fn next(&mut self) -> Option<(ParamSpace, usize, &'a T)> { - let spaces = ParamSpace::all(); - if self.space_index < spaces.len() { - let space = spaces[self.space_index]; - let index = self.elem_index; - let item = self.vec.get(space, index); - - self.elem_index += 1; - self.adjust_space(); - - Some((space, index, item)) - } else { - None - } - } - - fn size_hint(&self) -> (usize, Option) { - let size = self.vec.as_slice().len(); - (size, Some(size)) - } -} - -impl IntoIterator for VecPerParamSpace { - type Item = T; - type IntoIter = IntoIter; - - fn into_iter(self) -> IntoIter { - self.into_vec().into_iter() - } -} - -impl<'a,T> IntoIterator for &'a VecPerParamSpace { - type Item = &'a T; - type IntoIter = Iter<'a, T>; - - fn into_iter(self) -> Iter<'a, T> { - self.as_slice().into_iter() - } -} - - -/////////////////////////////////////////////////////////////////////////// -// Public trait `Subst` -// -// Just call `foo.subst(tcx, substs)` to perform a substitution across -// `foo`. Or use `foo.subst_spanned(tcx, substs, Some(span))` when -// there is more information available (for better errors). - -pub trait Subst<'tcx> : Sized { - fn subst(&self, tcx: &TyCtxt<'tcx>, substs: &Substs<'tcx>) -> Self { - self.subst_spanned(tcx, substs, None) - } - - fn subst_spanned(&self, tcx: &TyCtxt<'tcx>, - substs: &Substs<'tcx>, - span: Option) - -> Self; -} - -impl<'tcx, T:TypeFoldable<'tcx>> Subst<'tcx> for T { - fn subst_spanned(&self, - tcx: &TyCtxt<'tcx>, - substs: &Substs<'tcx>, - span: Option) - -> T - { - let mut folder = SubstFolder { tcx: tcx, - substs: substs, - span: span, - root_ty: None, - ty_stack_depth: 0, - region_binders_passed: 0 }; - (*self).fold_with(&mut folder) - } -} - -/////////////////////////////////////////////////////////////////////////// -// The actual substitution engine itself is a type folder. - -struct SubstFolder<'a, 'tcx: 'a> { - tcx: &'a TyCtxt<'tcx>, - substs: &'a Substs<'tcx>, - - // The location for which the substitution is performed, if available. - span: Option, - - // The root type that is being substituted, if available. - root_ty: Option>, - - // Depth of type stack - ty_stack_depth: usize, - - // Number of region binders we have passed through while doing the substitution - region_binders_passed: u32, -} - -impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { - fn tcx(&self) -> &TyCtxt<'tcx> { self.tcx } - - fn enter_region_binder(&mut self) { - self.region_binders_passed += 1; - } - - fn exit_region_binder(&mut self) { - self.region_binders_passed -= 1; - } - - fn fold_region(&mut self, r: ty::Region) -> ty::Region { - // Note: This routine only handles regions that are bound on - // type declarations and other outer declarations, not those - // bound in *fn types*. Region substitution of the bound - // regions that appear in a function signature is done using - // the specialized routine `ty::replace_late_regions()`. - match r { - ty::ReEarlyBound(data) => { - match self.substs.regions.opt_get(data.space, data.index as usize) { - Some(&r) => { - self.shift_region_through_binders(r) - } - None => { - let span = self.span.unwrap_or(DUMMY_SP); - self.tcx().sess.span_bug( - span, - &format!("Region parameter out of range \ - when substituting in region {} (root type={:?}) \ - (space={:?}, index={})", - data.name, - self.root_ty, - data.space, - data.index)); - } - } - } - _ => r - } - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.needs_subst() { - return t; - } - - // track the root type we were asked to substitute - let depth = self.ty_stack_depth; - if depth == 0 { - self.root_ty = Some(t); - } - self.ty_stack_depth += 1; - - let t1 = match t.sty { - ty::TyParam(p) => { - self.ty_for_param(p, t) - } - _ => { - t.super_fold_with(self) - } - }; - - assert_eq!(depth + 1, self.ty_stack_depth); - self.ty_stack_depth -= 1; - if depth == 0 { - self.root_ty = None; - } - - return t1; - } -} - -impl<'a,'tcx> SubstFolder<'a,'tcx> { - fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> { - // Look up the type in the substitutions. It really should be in there. - let opt_ty = self.substs.types.opt_get(p.space, p.idx as usize); - let ty = match opt_ty { - Some(t) => *t, - None => { - let span = self.span.unwrap_or(DUMMY_SP); - self.tcx().sess.span_bug( - span, - &format!("Type parameter `{:?}` ({:?}/{:?}/{}) out of range \ - when substituting (root type={:?}) substs={:?}", - p, - source_ty, - p.space, - p.idx, - self.root_ty, - self.substs)); - } - }; - - self.shift_regions_through_binders(ty) - } - - /// It is sometimes necessary to adjust the debruijn indices during substitution. This occurs - /// when we are substituting a type with escaping regions into a context where we have passed - /// through region binders. That's quite a mouthful. Let's see an example: - /// - /// ``` - /// type Func = fn(A); - /// type MetaFunc = for<'a> fn(Func<&'a int>) - /// ``` - /// - /// The type `MetaFunc`, when fully expanded, will be - /// - /// for<'a> fn(fn(&'a int)) - /// ^~ ^~ ^~~ - /// | | | - /// | | DebruijnIndex of 2 - /// Binders - /// - /// Here the `'a` lifetime is bound in the outer function, but appears as an argument of the - /// inner one. Therefore, that appearance will have a DebruijnIndex of 2, because we must skip - /// over the inner binder (remember that we count Debruijn indices from 1). However, in the - /// definition of `MetaFunc`, the binder is not visible, so the type `&'a int` will have a - /// debruijn index of 1. It's only during the substitution that we can see we must increase the - /// depth by 1 to account for the binder that we passed through. - /// - /// As a second example, consider this twist: - /// - /// ``` - /// type FuncTuple = (A,fn(A)); - /// type MetaFuncTuple = for<'a> fn(FuncTuple<&'a int>) - /// ``` - /// - /// Here the final type will be: - /// - /// for<'a> fn((&'a int, fn(&'a int))) - /// ^~~ ^~~ - /// | | - /// DebruijnIndex of 1 | - /// DebruijnIndex of 2 - /// - /// As indicated in the diagram, here the same type `&'a int` is substituted once, but in the - /// first case we do not increase the Debruijn index and in the second case we do. The reason - /// is that only in the second case have we passed through a fn binder. - fn shift_regions_through_binders(&self, ty: Ty<'tcx>) -> Ty<'tcx> { - debug!("shift_regions(ty={:?}, region_binders_passed={:?}, has_escaping_regions={:?})", - ty, self.region_binders_passed, ty.has_escaping_regions()); - - if self.region_binders_passed == 0 || !ty.has_escaping_regions() { - return ty; - } - - let result = ty::fold::shift_regions(self.tcx(), self.region_binders_passed, &ty); - debug!("shift_regions: shifted result = {:?}", result); - - result - } - - fn shift_region_through_binders(&self, region: ty::Region) -> ty::Region { - ty::fold::shift_region(region, self.region_binders_passed) - } -} diff --git a/src/librustc/middle/ty/trait_def.rs b/src/librustc/middle/ty/trait_def.rs deleted file mode 100644 index 3d7b3bf2634..00000000000 --- a/src/librustc/middle/ty/trait_def.rs +++ /dev/null @@ -1,282 +0,0 @@ -// Copyright 2012-2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use dep_graph::DepNode; -use middle::def_id::DefId; -use middle::traits::{self, specialization_graph}; -use middle::ty; -use middle::ty::fast_reject; -use middle::ty::{Ty, TyCtxt, TraitRef}; -use std::borrow::{Borrow}; -use std::cell::{Cell, Ref, RefCell}; -use syntax::ast::Name; -use rustc_front::hir; -use util::nodemap::FnvHashMap; - -/// As `TypeScheme` but for a trait ref. -pub struct TraitDef<'tcx> { - pub unsafety: hir::Unsafety, - - /// If `true`, then this trait had the `#[rustc_paren_sugar]` - /// attribute, indicating that it should be used with `Foo()` - /// sugar. This is a temporary thing -- eventually any trait wil - /// be usable with the sugar (or without it). - pub paren_sugar: bool, - - /// Generic type definitions. Note that `Self` is listed in here - /// as having a single bound, the trait itself (e.g., in the trait - /// `Eq`, there is a single bound `Self : Eq`). This is so that - /// default methods get to assume that the `Self` parameters - /// implements the trait. - pub generics: ty::Generics<'tcx>, - - pub trait_ref: ty::TraitRef<'tcx>, - - /// A list of the associated types defined in this trait. Useful - /// for resolving `X::Foo` type markers. - pub associated_type_names: Vec, - - // Impls of this trait. To allow for quicker lookup, the impls are indexed - // by a simplified version of their Self type: impls with a simplifiable - // Self are stored in nonblanket_impls keyed by it, while all other impls - // are stored in blanket_impls. - // - // These lists are tracked by `DepNode::TraitImpls`; we don't use - // a DepTrackingMap but instead have the `TraitDef` insert the - // required reads/writes. - - /// Impls of the trait. - nonblanket_impls: RefCell< - FnvHashMap> - >, - - /// Blanket impls associated with the trait. - blanket_impls: RefCell>, - - /// The specialization order for impls of this trait. - pub specialization_graph: RefCell, - - /// Various flags - pub flags: Cell -} - -impl<'tcx> TraitDef<'tcx> { - pub fn new(unsafety: hir::Unsafety, - paren_sugar: bool, - generics: ty::Generics<'tcx>, - trait_ref: ty::TraitRef<'tcx>, - associated_type_names: Vec) - -> TraitDef<'tcx> { - TraitDef { - paren_sugar: paren_sugar, - unsafety: unsafety, - generics: generics, - trait_ref: trait_ref, - associated_type_names: associated_type_names, - nonblanket_impls: RefCell::new(FnvHashMap()), - blanket_impls: RefCell::new(vec![]), - flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS), - specialization_graph: RefCell::new(traits::specialization_graph::Graph::new()), - } - } - - pub fn def_id(&self) -> DefId { - self.trait_ref.def_id - } - - // returns None if not yet calculated - pub fn object_safety(&self) -> Option { - if self.flags.get().intersects(TraitFlags::OBJECT_SAFETY_VALID) { - Some(self.flags.get().intersects(TraitFlags::IS_OBJECT_SAFE)) - } else { - None - } - } - - pub fn set_object_safety(&self, is_safe: bool) { - assert!(self.object_safety().map(|cs| cs == is_safe).unwrap_or(true)); - self.flags.set( - self.flags.get() | if is_safe { - TraitFlags::OBJECT_SAFETY_VALID | TraitFlags::IS_OBJECT_SAFE - } else { - TraitFlags::OBJECT_SAFETY_VALID - } - ); - } - - fn write_trait_impls(&self, tcx: &TyCtxt<'tcx>) { - tcx.dep_graph.write(DepNode::TraitImpls(self.trait_ref.def_id)); - } - - fn read_trait_impls(&self, tcx: &TyCtxt<'tcx>) { - tcx.dep_graph.read(DepNode::TraitImpls(self.trait_ref.def_id)); - } - - /// Records a basic trait-to-implementation mapping. - /// - /// Returns `true` iff the impl has not previously been recorded. - fn record_impl(&self, - tcx: &TyCtxt<'tcx>, - impl_def_id: DefId, - impl_trait_ref: TraitRef<'tcx>) - -> bool { - debug!("TraitDef::record_impl for {:?}, from {:?}", - self, impl_trait_ref); - - // Record the write into the impl set, but only for local - // impls: external impls are handled differently. - if impl_def_id.is_local() { - self.write_trait_impls(tcx); - } - - // We don't want to borrow_mut after we already populated all impls, - // so check if an impl is present with an immutable borrow first. - if let Some(sty) = fast_reject::simplify_type(tcx, - impl_trait_ref.self_ty(), false) { - if let Some(is) = self.nonblanket_impls.borrow().get(&sty) { - if is.contains(&impl_def_id) { - return false; // duplicate - skip - } - } - - self.nonblanket_impls.borrow_mut().entry(sty).or_insert(vec![]).push(impl_def_id) - } else { - if self.blanket_impls.borrow().contains(&impl_def_id) { - return false; // duplicate - skip - } - self.blanket_impls.borrow_mut().push(impl_def_id) - } - - true - } - - /// Records a trait-to-implementation mapping for a crate-local impl. - pub fn record_local_impl(&self, - tcx: &TyCtxt<'tcx>, - impl_def_id: DefId, - impl_trait_ref: TraitRef<'tcx>) { - assert!(impl_def_id.is_local()); - let was_new = self.record_impl(tcx, impl_def_id, impl_trait_ref); - assert!(was_new); - } - - /// Records a trait-to-implementation mapping for a non-local impl. - /// - /// The `parent_impl` is the immediately-less-specialized impl, or the - /// trait's def ID if the impl is is not a specialization -- information that - /// should be pulled from the metadata. - pub fn record_remote_impl(&self, - tcx: &TyCtxt<'tcx>, - impl_def_id: DefId, - impl_trait_ref: TraitRef<'tcx>, - parent_impl: DefId) { - assert!(!impl_def_id.is_local()); - - // if the impl has not previously been recorded - if self.record_impl(tcx, impl_def_id, impl_trait_ref) { - // if the impl is non-local, it's placed directly into the - // specialization graph using parent information drawn from metadata. - self.specialization_graph.borrow_mut() - .record_impl_from_cstore(parent_impl, impl_def_id) - } - } - - /// Adds a local impl into the specialization graph, returning an error with - /// overlap information if the impl overlaps but does not specialize an - /// existing impl. - pub fn add_impl_for_specialization<'a>(&self, - tcx: &'a TyCtxt<'tcx>, - impl_def_id: DefId) - -> Result<(), traits::Overlap<'a, 'tcx>> { - assert!(impl_def_id.is_local()); - - self.specialization_graph.borrow_mut() - .insert(tcx, impl_def_id) - } - - pub fn ancestors<'a>(&'a self, of_impl: DefId) -> specialization_graph::Ancestors<'a, 'tcx> { - specialization_graph::ancestors(self, of_impl) - } - - pub fn for_each_impl(&self, tcx: &TyCtxt<'tcx>, mut f: F) { - self.read_trait_impls(tcx); - tcx.populate_implementations_for_trait_if_necessary(self.trait_ref.def_id); - - for &impl_def_id in self.blanket_impls.borrow().iter() { - f(impl_def_id); - } - - for v in self.nonblanket_impls.borrow().values() { - for &impl_def_id in v { - f(impl_def_id); - } - } - } - - /// Iterate over every impl that could possibly match the - /// self-type `self_ty`. - pub fn for_each_relevant_impl(&self, - tcx: &TyCtxt<'tcx>, - self_ty: Ty<'tcx>, - mut f: F) - { - self.read_trait_impls(tcx); - - tcx.populate_implementations_for_trait_if_necessary(self.trait_ref.def_id); - - for &impl_def_id in self.blanket_impls.borrow().iter() { - f(impl_def_id); - } - - // simplify_type(.., false) basically replaces type parameters and - // projections with infer-variables. This is, of course, done on - // the impl trait-ref when it is instantiated, but not on the - // predicate trait-ref which is passed here. - // - // for example, if we match `S: Copy` against an impl like - // `impl Copy for Option`, we replace the type variable - // in `Option` with an infer variable, to `Option<_>` (this - // doesn't actually change fast_reject output), but we don't - // replace `S` with anything - this impl of course can't be - // selected, and as there are hundreds of similar impls, - // considering them would significantly harm performance. - if let Some(simp) = fast_reject::simplify_type(tcx, self_ty, true) { - if let Some(impls) = self.nonblanket_impls.borrow().get(&simp) { - for &impl_def_id in impls { - f(impl_def_id); - } - } - } else { - for v in self.nonblanket_impls.borrow().values() { - for &impl_def_id in v { - f(impl_def_id); - } - } - } - } - - pub fn borrow_impl_lists<'s>(&'s self, tcx: &TyCtxt<'tcx>) - -> (Ref<'s, Vec>, - Ref<'s, FnvHashMap>>) { - self.read_trait_impls(tcx); - (self.blanket_impls.borrow(), self.nonblanket_impls.borrow()) - } - -} - -bitflags! { - flags TraitFlags: u32 { - const NO_TRAIT_FLAGS = 0, - const HAS_DEFAULT_IMPL = 1 << 0, - const IS_OBJECT_SAFE = 1 << 1, - const OBJECT_SAFETY_VALID = 1 << 2, - const IMPLS_VALID = 1 << 3, - } -} diff --git a/src/librustc/middle/ty/util.rs b/src/librustc/middle/ty/util.rs deleted file mode 100644 index f6c4390b83c..00000000000 --- a/src/librustc/middle/ty/util.rs +++ /dev/null @@ -1,786 +0,0 @@ -// Copyright 2012-2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! misc. type-system utilities too small to deserve their own file - -use back::svh::Svh; -use middle::const_eval::{self, ConstVal, ErrKind}; -use middle::const_eval::EvalHint::UncheckedExprHint; -use middle::def_id::DefId; -use middle::ty::subst; -use middle::infer; -use middle::pat_util; -use middle::traits::{self, ProjectionMode}; -use middle::ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable}; -use middle::ty::{Disr, ParameterEnvironment}; -use middle::ty::TypeVariants::*; - -use rustc_const_eval::{ConstInt, ConstIsize, ConstUsize}; - -use std::cmp; -use std::hash::{Hash, SipHasher, Hasher}; -use syntax::ast::{self, Name}; -use syntax::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt}; -use syntax::codemap::Span; - -use rustc_front::hir; - -pub trait IntTypeExt { - fn to_ty<'tcx>(&self, cx: &TyCtxt<'tcx>) -> Ty<'tcx>; - fn disr_incr(&self, val: Disr) -> Option; - fn assert_ty_matches(&self, val: Disr); - fn initial_discriminant(&self, tcx: &TyCtxt) -> Disr; -} - -impl IntTypeExt for attr::IntType { - fn to_ty<'tcx>(&self, cx: &TyCtxt<'tcx>) -> Ty<'tcx> { - match *self { - SignedInt(ast::IntTy::I8) => cx.types.i8, - SignedInt(ast::IntTy::I16) => cx.types.i16, - SignedInt(ast::IntTy::I32) => cx.types.i32, - SignedInt(ast::IntTy::I64) => cx.types.i64, - SignedInt(ast::IntTy::Is) => cx.types.isize, - UnsignedInt(ast::UintTy::U8) => cx.types.u8, - UnsignedInt(ast::UintTy::U16) => cx.types.u16, - UnsignedInt(ast::UintTy::U32) => cx.types.u32, - UnsignedInt(ast::UintTy::U64) => cx.types.u64, - UnsignedInt(ast::UintTy::Us) => cx.types.usize, - } - } - - fn initial_discriminant(&self, tcx: &TyCtxt) -> Disr { - match *self { - SignedInt(ast::IntTy::I8) => ConstInt::I8(0), - SignedInt(ast::IntTy::I16) => ConstInt::I16(0), - SignedInt(ast::IntTy::I32) => ConstInt::I32(0), - SignedInt(ast::IntTy::I64) => ConstInt::I64(0), - SignedInt(ast::IntTy::Is) => match tcx.sess.target.int_type { - ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32(0)), - ast::IntTy::I64 => ConstInt::Isize(ConstIsize::Is64(0)), - _ => unreachable!(), - }, - UnsignedInt(ast::UintTy::U8) => ConstInt::U8(0), - UnsignedInt(ast::UintTy::U16) => ConstInt::U16(0), - UnsignedInt(ast::UintTy::U32) => ConstInt::U32(0), - UnsignedInt(ast::UintTy::U64) => ConstInt::U64(0), - UnsignedInt(ast::UintTy::Us) => match tcx.sess.target.uint_type { - ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32(0)), - ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64(0)), - _ => unreachable!(), - }, - } - } - - fn assert_ty_matches(&self, val: Disr) { - match (*self, val) { - (SignedInt(ast::IntTy::I8), ConstInt::I8(_)) => {}, - (SignedInt(ast::IntTy::I16), ConstInt::I16(_)) => {}, - (SignedInt(ast::IntTy::I32), ConstInt::I32(_)) => {}, - (SignedInt(ast::IntTy::I64), ConstInt::I64(_)) => {}, - (SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) => {}, - (UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) => {}, - (UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) => {}, - (UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) => {}, - (UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) => {}, - (UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => {}, - _ => panic!("disr type mismatch: {:?} vs {:?}", self, val), - } - } - - fn disr_incr(&self, val: Disr) -> Option { - self.assert_ty_matches(val); - (val + ConstInt::Infer(1)).ok() - } -} - - -#[derive(Copy, Clone)] -pub enum CopyImplementationError { - InfrigingField(Name), - InfrigingVariant(Name), - NotAnAdt, - HasDestructor -} - -/// Describes whether a type is representable. For types that are not -/// representable, 'SelfRecursive' and 'ContainsRecursive' are used to -/// distinguish between types that are recursive with themselves and types that -/// contain a different recursive type. These cases can therefore be treated -/// differently when reporting errors. -/// -/// The ordering of the cases is significant. They are sorted so that cmp::max -/// will keep the "more erroneous" of two values. -#[derive(Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Debug)] -pub enum Representability { - Representable, - ContainsRecursive, - SelfRecursive, -} - -impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { - pub fn can_type_implement_copy(&self, self_type: Ty<'tcx>, span: Span) - -> Result<(),CopyImplementationError> { - let tcx = self.tcx; - - // FIXME: (@jroesch) float this code up - let infcx = infer::new_infer_ctxt(tcx, - &tcx.tables, - Some(self.clone()), - ProjectionMode::Topmost); - - let adt = match self_type.sty { - ty::TyStruct(struct_def, substs) => { - for field in struct_def.all_fields() { - let field_ty = field.ty(tcx, substs); - if infcx.type_moves_by_default(field_ty, span) { - return Err(CopyImplementationError::InfrigingField( - field.name)) - } - } - struct_def - } - ty::TyEnum(enum_def, substs) => { - for variant in &enum_def.variants { - for field in &variant.fields { - let field_ty = field.ty(tcx, substs); - if infcx.type_moves_by_default(field_ty, span) { - return Err(CopyImplementationError::InfrigingVariant( - variant.name)) - } - } - } - enum_def - } - _ => return Err(CopyImplementationError::NotAnAdt), - }; - - if adt.has_dtor() { - return Err(CopyImplementationError::HasDestructor) - } - - Ok(()) - } -} - -impl<'tcx> TyCtxt<'tcx> { - pub fn pat_contains_ref_binding(&self, pat: &hir::Pat) -> Option { - pat_util::pat_contains_ref_binding(&self.def_map, pat) - } - - pub fn arm_contains_ref_binding(&self, arm: &hir::Arm) -> Option { - pat_util::arm_contains_ref_binding(&self.def_map, arm) - } - - /// Returns the type of element at index `i` in tuple or tuple-like type `t`. - /// For an enum `t`, `variant` is None only if `t` is a univariant enum. - pub fn positional_element_ty(&self, - ty: Ty<'tcx>, - i: usize, - variant: Option) -> Option> { - match (&ty.sty, variant) { - (&TyStruct(def, substs), None) => { - def.struct_variant().fields.get(i).map(|f| f.ty(self, substs)) - } - (&TyEnum(def, substs), Some(vid)) => { - def.variant_with_id(vid).fields.get(i).map(|f| f.ty(self, substs)) - } - (&TyEnum(def, substs), None) => { - assert!(def.is_univariant()); - def.variants[0].fields.get(i).map(|f| f.ty(self, substs)) - } - (&TyTuple(ref v), None) => v.get(i).cloned(), - _ => None - } - } - - /// Returns the type of element at field `n` in struct or struct-like type `t`. - /// For an enum `t`, `variant` must be some def id. - pub fn named_element_ty(&self, - ty: Ty<'tcx>, - n: Name, - variant: Option) -> Option> { - match (&ty.sty, variant) { - (&TyStruct(def, substs), None) => { - def.struct_variant().find_field_named(n).map(|f| f.ty(self, substs)) - } - (&TyEnum(def, substs), Some(vid)) => { - def.variant_with_id(vid).find_field_named(n).map(|f| f.ty(self, substs)) - } - _ => return None - } - } - - /// Returns the IntType representation. - /// This used to ensure `int_ty` doesn't contain `usize` and `isize` - /// by converting them to their actual types. That doesn't happen anymore. - pub fn enum_repr_type(&self, opt_hint: Option<&attr::ReprAttr>) -> attr::IntType { - match opt_hint { - // Feed in the given type - Some(&attr::ReprInt(_, int_t)) => int_t, - // ... but provide sensible default if none provided - // - // NB. Historically `fn enum_variants` generate i64 here, while - // rustc_typeck::check would generate isize. - _ => SignedInt(ast::IntTy::Is), - } - } - - /// Returns the deeply last field of nested structures, or the same type, - /// if not a structure at all. Corresponds to the only possible unsized - /// field, and its type can be used to determine unsizing strategy. - pub fn struct_tail(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { - while let TyStruct(def, substs) = ty.sty { - match def.struct_variant().fields.last() { - Some(f) => ty = f.ty(self, substs), - None => break - } - } - ty - } - - /// Same as applying struct_tail on `source` and `target`, but only - /// keeps going as long as the two types are instances of the same - /// structure definitions. - /// For `(Foo>, Foo)`, the result will be `(Foo, Trait)`, - /// whereas struct_tail produces `T`, and `Trait`, respectively. - pub fn struct_lockstep_tails(&self, - source: Ty<'tcx>, - target: Ty<'tcx>) - -> (Ty<'tcx>, Ty<'tcx>) { - let (mut a, mut b) = (source, target); - while let (&TyStruct(a_def, a_substs), &TyStruct(b_def, b_substs)) = (&a.sty, &b.sty) { - if a_def != b_def { - break; - } - if let Some(f) = a_def.struct_variant().fields.last() { - a = f.ty(self, a_substs); - b = f.ty(self, b_substs); - } else { - break; - } - } - (a, b) - } - - /// Returns the repeat count for a repeating vector expression. - pub fn eval_repeat_count(&self, count_expr: &hir::Expr) -> usize { - let hint = UncheckedExprHint(self.types.usize); - match const_eval::eval_const_expr_partial(self, count_expr, hint, None) { - Ok(ConstVal::Integral(ConstInt::Usize(count))) => { - let val = count.as_u64(self.sess.target.uint_type); - assert_eq!(val as usize as u64, val); - val as usize - }, - Ok(const_val) => { - span_err!(self.sess, count_expr.span, E0306, - "expected positive integer for repeat count, found {}", - const_val.description()); - 0 - } - Err(err) => { - let err_msg = match count_expr.node { - hir::ExprPath(None, hir::Path { - global: false, - ref segments, - .. - }) if segments.len() == 1 => - format!("found variable"), - _ => match err.kind { - ErrKind::MiscCatchAll => format!("but found {}", err.description()), - _ => format!("but {}", err.description()) - } - }; - span_err!(self.sess, count_expr.span, E0307, - "expected constant integer for repeat count, {}", err_msg); - 0 - } - } - } - - /// Given a set of predicates that apply to an object type, returns - /// the region bounds that the (erased) `Self` type must - /// outlive. Precisely *because* the `Self` type is erased, the - /// parameter `erased_self_ty` must be supplied to indicate what type - /// has been used to represent `Self` in the predicates - /// themselves. This should really be a unique type; `FreshTy(0)` is a - /// popular choice. - /// - /// NB: in some cases, particularly around higher-ranked bounds, - /// this function returns a kind of conservative approximation. - /// That is, all regions returned by this function are definitely - /// required, but there may be other region bounds that are not - /// returned, as well as requirements like `for<'a> T: 'a`. - /// - /// Requires that trait definitions have been processed so that we can - /// elaborate predicates and walk supertraits. - pub fn required_region_bounds(&self, - erased_self_ty: Ty<'tcx>, - predicates: Vec>) - -> Vec { - debug!("required_region_bounds(erased_self_ty={:?}, predicates={:?})", - erased_self_ty, - predicates); - - assert!(!erased_self_ty.has_escaping_regions()); - - traits::elaborate_predicates(self, predicates) - .filter_map(|predicate| { - match predicate { - ty::Predicate::Projection(..) | - ty::Predicate::Trait(..) | - ty::Predicate::Equate(..) | - ty::Predicate::WellFormed(..) | - ty::Predicate::ObjectSafe(..) | - ty::Predicate::RegionOutlives(..) => { - None - } - ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t, r))) => { - // Search for a bound of the form `erased_self_ty - // : 'a`, but be wary of something like `for<'a> - // erased_self_ty : 'a` (we interpret a - // higher-ranked bound like that as 'static, - // though at present the code in `fulfill.rs` - // considers such bounds to be unsatisfiable, so - // it's kind of a moot point since you could never - // construct such an object, but this seems - // correct even if that code changes). - if t == erased_self_ty && !r.has_escaping_regions() { - Some(r) - } else { - None - } - } - } - }) - .collect() - } - - /// Creates a hash of the type `Ty` which will be the same no matter what crate - /// context it's calculated within. This is used by the `type_id` intrinsic. - pub fn hash_crate_independent(&self, ty: Ty<'tcx>, svh: &Svh) -> u64 { - let mut state = SipHasher::new(); - helper(self, ty, svh, &mut state); - return state.finish(); - - fn helper<'tcx>(tcx: &TyCtxt<'tcx>, ty: Ty<'tcx>, svh: &Svh, - state: &mut SipHasher) { - macro_rules! byte { ($b:expr) => { ($b as u8).hash(state) } } - macro_rules! hash { ($e:expr) => { $e.hash(state) } } - - let region = |state: &mut SipHasher, r: ty::Region| { - match r { - ty::ReStatic => {} - ty::ReLateBound(db, ty::BrAnon(i)) => { - db.hash(state); - i.hash(state); - } - ty::ReEmpty | - ty::ReEarlyBound(..) | - ty::ReLateBound(..) | - ty::ReFree(..) | - ty::ReScope(..) | - ty::ReVar(..) | - ty::ReSkolemized(..) => { - tcx.sess.bug("unexpected region found when hashing a type") - } - } - }; - let did = |state: &mut SipHasher, did: DefId| { - let h = if did.is_local() { - svh.clone() - } else { - tcx.sess.cstore.crate_hash(did.krate) - }; - h.as_str().hash(state); - did.index.hash(state); - }; - let mt = |state: &mut SipHasher, mt: TypeAndMut| { - mt.mutbl.hash(state); - }; - let fn_sig = |state: &mut SipHasher, sig: &ty::Binder>| { - let sig = tcx.anonymize_late_bound_regions(sig).0; - for a in &sig.inputs { helper(tcx, *a, svh, state); } - if let ty::FnConverging(output) = sig.output { - helper(tcx, output, svh, state); - } - }; - ty.maybe_walk(|ty| { - match ty.sty { - TyBool => byte!(2), - TyChar => byte!(3), - TyInt(i) => { - byte!(4); - hash!(i); - } - TyUint(u) => { - byte!(5); - hash!(u); - } - TyFloat(f) => { - byte!(6); - hash!(f); - } - TyStr => { - byte!(7); - } - TyEnum(d, _) => { - byte!(8); - did(state, d.did); - } - TyBox(_) => { - byte!(9); - } - TyArray(_, n) => { - byte!(10); - n.hash(state); - } - TySlice(_) => { - byte!(11); - } - TyRawPtr(m) => { - byte!(12); - mt(state, m); - } - TyRef(r, m) => { - byte!(13); - region(state, *r); - mt(state, m); - } - TyFnDef(def_id, _, _) => { - byte!(14); - hash!(def_id); - } - TyFnPtr(ref b) => { - byte!(15); - hash!(b.unsafety); - hash!(b.abi); - fn_sig(state, &b.sig); - return false; - } - TyTrait(ref data) => { - byte!(17); - did(state, data.principal_def_id()); - hash!(data.bounds); - - let principal = tcx.anonymize_late_bound_regions(&data.principal).0; - for subty in &principal.substs.types { - helper(tcx, subty, svh, state); - } - - return false; - } - TyStruct(d, _) => { - byte!(18); - did(state, d.did); - } - TyTuple(ref inner) => { - byte!(19); - hash!(inner.len()); - } - TyParam(p) => { - byte!(20); - hash!(p.space); - hash!(p.idx); - hash!(p.name.as_str()); - } - TyInfer(_) => unreachable!(), - TyError => byte!(21), - TyClosure(d, _) => { - byte!(22); - did(state, d); - } - TyProjection(ref data) => { - byte!(23); - did(state, data.trait_ref.def_id); - hash!(data.item_name.as_str()); - } - } - true - }); - } - } - - /// Returns true if this ADT is a dtorck type. - /// - /// Invoking the destructor of a dtorck type during usual cleanup - /// (e.g. the glue emitted for stack unwinding) requires all - /// lifetimes in the type-structure of `adt` to strictly outlive - /// the adt value itself. - /// - /// If `adt` is not dtorck, then the adt's destructor can be - /// invoked even when there are lifetimes in the type-structure of - /// `adt` that do not strictly outlive the adt value itself. - /// (This allows programs to make cyclic structures without - /// resorting to unasfe means; see RFCs 769 and 1238). - pub fn is_adt_dtorck(&self, adt: ty::AdtDef<'tcx>) -> bool { - let dtor_method = match adt.destructor() { - Some(dtor) => dtor, - None => return false - }; - - // RFC 1238: if the destructor method is tagged with the - // attribute `unsafe_destructor_blind_to_params`, then the - // compiler is being instructed to *assume* that the - // destructor will not access borrowed data, - // even if such data is otherwise reachable. - // - // Such access can be in plain sight (e.g. dereferencing - // `*foo.0` of `Foo<'a>(&'a u32)`) or indirectly hidden - // (e.g. calling `foo.0.clone()` of `Foo`). - return !self.has_attr(dtor_method, "unsafe_destructor_blind_to_params"); - } -} - -impl<'tcx> ty::TyS<'tcx> { - fn impls_bound<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, - bound: ty::BuiltinBound, - span: Span) - -> bool - { - let tcx = param_env.tcx; - let infcx = infer::new_infer_ctxt(tcx, - &tcx.tables, - Some(param_env.clone()), - ProjectionMode::Topmost); - - let is_impld = traits::type_known_to_meet_builtin_bound(&infcx, - self, bound, span); - - debug!("Ty::impls_bound({:?}, {:?}) = {:?}", - self, bound, is_impld); - - is_impld - } - - // FIXME (@jroesch): I made this public to use it, not sure if should be private - pub fn moves_by_default<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, - span: Span) -> bool { - if self.flags.get().intersects(TypeFlags::MOVENESS_CACHED) { - return self.flags.get().intersects(TypeFlags::MOVES_BY_DEFAULT); - } - - assert!(!self.needs_infer()); - - // Fast-path for primitive types - let result = match self.sty { - TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | - TyRawPtr(..) | TyFnDef(..) | TyFnPtr(_) | TyRef(_, TypeAndMut { - mutbl: hir::MutImmutable, .. - }) => Some(false), - - TyStr | TyBox(..) | TyRef(_, TypeAndMut { - mutbl: hir::MutMutable, .. - }) => Some(true), - - TyArray(..) | TySlice(_) | TyTrait(..) | TyTuple(..) | - TyClosure(..) | TyEnum(..) | TyStruct(..) | - TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None - }.unwrap_or_else(|| !self.impls_bound(param_env, ty::BoundCopy, span)); - - if !self.has_param_types() && !self.has_self_ty() { - self.flags.set(self.flags.get() | if result { - TypeFlags::MOVENESS_CACHED | TypeFlags::MOVES_BY_DEFAULT - } else { - TypeFlags::MOVENESS_CACHED - }); - } - - result - } - - #[inline] - pub fn is_sized<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, - span: Span) -> bool - { - if self.flags.get().intersects(TypeFlags::SIZEDNESS_CACHED) { - return self.flags.get().intersects(TypeFlags::IS_SIZED); - } - - self.is_sized_uncached(param_env, span) - } - - fn is_sized_uncached<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, - span: Span) -> bool { - assert!(!self.needs_infer()); - - // Fast-path for primitive types - let result = match self.sty { - TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | - TyBox(..) | TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) | - TyArray(..) | TyTuple(..) | TyClosure(..) => Some(true), - - TyStr | TyTrait(..) | TySlice(_) => Some(false), - - TyEnum(..) | TyStruct(..) | TyProjection(..) | TyParam(..) | - TyInfer(..) | TyError => None - }.unwrap_or_else(|| self.impls_bound(param_env, ty::BoundSized, span)); - - if !self.has_param_types() && !self.has_self_ty() { - self.flags.set(self.flags.get() | if result { - TypeFlags::SIZEDNESS_CACHED | TypeFlags::IS_SIZED - } else { - TypeFlags::SIZEDNESS_CACHED - }); - } - - result - } - - - /// Check whether a type is representable. This means it cannot contain unboxed - /// structural recursion. This check is needed for structs and enums. - pub fn is_representable(&'tcx self, cx: &TyCtxt<'tcx>, sp: Span) -> Representability { - - // Iterate until something non-representable is found - fn find_nonrepresentable<'tcx, It: Iterator>>(cx: &TyCtxt<'tcx>, - sp: Span, - seen: &mut Vec>, - iter: It) - -> Representability { - iter.fold(Representability::Representable, - |r, ty| cmp::max(r, is_type_structurally_recursive(cx, sp, seen, ty))) - } - - fn are_inner_types_recursive<'tcx>(cx: &TyCtxt<'tcx>, sp: Span, - seen: &mut Vec>, ty: Ty<'tcx>) - -> Representability { - match ty.sty { - TyTuple(ref ts) => { - find_nonrepresentable(cx, sp, seen, ts.iter().cloned()) - } - // Fixed-length vectors. - // FIXME(#11924) Behavior undecided for zero-length vectors. - TyArray(ty, _) => { - is_type_structurally_recursive(cx, sp, seen, ty) - } - TyStruct(def, substs) | TyEnum(def, substs) => { - find_nonrepresentable(cx, - sp, - seen, - def.all_fields().map(|f| f.ty(cx, substs))) - } - TyClosure(..) => { - // this check is run on type definitions, so we don't expect - // to see closure types - cx.sess.bug(&format!("requires check invoked on inapplicable type: {:?}", ty)) - } - _ => Representability::Representable, - } - } - - fn same_struct_or_enum<'tcx>(ty: Ty<'tcx>, def: ty::AdtDef<'tcx>) -> bool { - match ty.sty { - TyStruct(ty_def, _) | TyEnum(ty_def, _) => { - ty_def == def - } - _ => false - } - } - - fn same_type<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - match (&a.sty, &b.sty) { - (&TyStruct(did_a, ref substs_a), &TyStruct(did_b, ref substs_b)) | - (&TyEnum(did_a, ref substs_a), &TyEnum(did_b, ref substs_b)) => { - if did_a != did_b { - return false; - } - - let types_a = substs_a.types.get_slice(subst::TypeSpace); - let types_b = substs_b.types.get_slice(subst::TypeSpace); - - let mut pairs = types_a.iter().zip(types_b); - - pairs.all(|(&a, &b)| same_type(a, b)) - } - _ => { - a == b - } - } - } - - // Does the type `ty` directly (without indirection through a pointer) - // contain any types on stack `seen`? - fn is_type_structurally_recursive<'tcx>(cx: &TyCtxt<'tcx>, - sp: Span, - seen: &mut Vec>, - ty: Ty<'tcx>) -> Representability { - debug!("is_type_structurally_recursive: {:?}", ty); - - match ty.sty { - TyStruct(def, _) | TyEnum(def, _) => { - { - // Iterate through stack of previously seen types. - let mut iter = seen.iter(); - - // The first item in `seen` is the type we are actually curious about. - // We want to return SelfRecursive if this type contains itself. - // It is important that we DON'T take generic parameters into account - // for this check, so that Bar in this example counts as SelfRecursive: - // - // struct Foo; - // struct Bar { x: Bar } - - match iter.next() { - Some(&seen_type) => { - if same_struct_or_enum(seen_type, def) { - debug!("SelfRecursive: {:?} contains {:?}", - seen_type, - ty); - return Representability::SelfRecursive; - } - } - None => {} - } - - // We also need to know whether the first item contains other types - // that are structurally recursive. If we don't catch this case, we - // will recurse infinitely for some inputs. - // - // It is important that we DO take generic parameters into account - // here, so that code like this is considered SelfRecursive, not - // ContainsRecursive: - // - // struct Foo { Option> } - - for &seen_type in iter { - if same_type(ty, seen_type) { - debug!("ContainsRecursive: {:?} contains {:?}", - seen_type, - ty); - return Representability::ContainsRecursive; - } - } - } - - // For structs and enums, track all previously seen types by pushing them - // onto the 'seen' stack. - seen.push(ty); - let out = are_inner_types_recursive(cx, sp, seen, ty); - seen.pop(); - out - } - _ => { - // No need to push in other cases. - are_inner_types_recursive(cx, sp, seen, ty) - } - } - } - - debug!("is_type_representable: {:?}", self); - - // To avoid a stack overflow when checking an enum variant or struct that - // contains a different, structurally recursive type, maintain a stack - // of seen types and check recursion for each of them (issues #3008, #3779). - let mut seen: Vec = Vec::new(); - let r = is_type_structurally_recursive(cx, sp, &mut seen, self); - debug!("is_type_representable: {:?} is {:?}", self, r); - r - } -} diff --git a/src/librustc/middle/ty/walk.rs b/src/librustc/middle/ty/walk.rs deleted file mode 100644 index b6d93ecf78b..00000000000 --- a/src/librustc/middle/ty/walk.rs +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2012-2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! An iterator over the type substructure. -//! WARNING: this does not keep track of the region depth. - -use middle::ty::{self, Ty}; -use std::iter::Iterator; -use std::vec::IntoIter; - -pub struct TypeWalker<'tcx> { - stack: Vec>, - last_subtree: usize, -} - -impl<'tcx> TypeWalker<'tcx> { - pub fn new(ty: Ty<'tcx>) -> TypeWalker<'tcx> { - TypeWalker { stack: vec!(ty), last_subtree: 1, } - } - - /// Skips the subtree of types corresponding to the last type - /// returned by `next()`. - /// - /// Example: Imagine you are walking `Foo, usize>`. - /// - /// ``` - /// let mut iter: TypeWalker = ...; - /// iter.next(); // yields Foo - /// iter.next(); // yields Bar - /// iter.skip_current_subtree(); // skips int - /// iter.next(); // yields usize - /// ``` - pub fn skip_current_subtree(&mut self) { - self.stack.truncate(self.last_subtree); - } -} - -impl<'tcx> Iterator for TypeWalker<'tcx> { - type Item = Ty<'tcx>; - - fn next(&mut self) -> Option> { - debug!("next(): stack={:?}", self.stack); - match self.stack.pop() { - None => { - return None; - } - Some(ty) => { - self.last_subtree = self.stack.len(); - push_subtypes(&mut self.stack, ty); - debug!("next: stack={:?}", self.stack); - Some(ty) - } - } - } -} - -pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> IntoIter> { - let mut stack = vec![]; - push_subtypes(&mut stack, ty); - stack.into_iter() -} - -fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { - match parent_ty.sty { - ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | - ty::TyStr | ty::TyInfer(_) | ty::TyParam(_) | ty::TyError => { - } - ty::TyBox(ty) | ty::TyArray(ty, _) | ty::TySlice(ty) => { - stack.push(ty); - } - ty::TyRawPtr(ref mt) | ty::TyRef(_, ref mt) => { - stack.push(mt.ty); - } - ty::TyProjection(ref data) => { - push_reversed(stack, data.trait_ref.substs.types.as_slice()); - } - ty::TyTrait(box ty::TraitTy { ref principal, ref bounds }) => { - push_reversed(stack, principal.substs().types.as_slice()); - push_reversed(stack, &bounds.projection_bounds.iter().map(|pred| { - pred.0.ty - }).collect::>()); - } - ty::TyEnum(_, ref substs) | - ty::TyStruct(_, ref substs) => { - push_reversed(stack, substs.types.as_slice()); - } - ty::TyClosure(_, ref substs) => { - push_reversed(stack, substs.func_substs.types.as_slice()); - push_reversed(stack, &substs.upvar_tys); - } - ty::TyTuple(ref ts) => { - push_reversed(stack, ts); - } - ty::TyFnDef(_, substs, ref ft) => { - push_reversed(stack, substs.types.as_slice()); - push_sig_subtypes(stack, &ft.sig); - } - ty::TyFnPtr(ref ft) => { - push_sig_subtypes(stack, &ft.sig); - } - } -} - -fn push_sig_subtypes<'tcx>(stack: &mut Vec>, sig: &ty::PolyFnSig<'tcx>) { - match sig.0.output { - ty::FnConverging(output) => { stack.push(output); } - ty::FnDiverging => { } - } - push_reversed(stack, &sig.0.inputs); -} - -fn push_reversed<'tcx>(stack: &mut Vec>, tys: &[Ty<'tcx>]) { - // We push slices on the stack in reverse order so as to - // maintain a pre-order traversal. As of the time of this - // writing, the fact that the traversal is pre-order is not - // known to be significant to any code, but it seems like the - // natural order one would expect (basically, the order of the - // types as they are written). - for &ty in tys.iter().rev() { - stack.push(ty); - } -} diff --git a/src/librustc/middle/ty/wf.rs b/src/librustc/middle/ty/wf.rs deleted file mode 100644 index 1becdb14fa5..00000000000 --- a/src/librustc/middle/ty/wf.rs +++ /dev/null @@ -1,509 +0,0 @@ -// Copyright 2012-2013 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use middle::def_id::DefId; -use middle::infer::InferCtxt; -use middle::ty::outlives::{self, Component}; -use middle::ty::subst::Substs; -use middle::traits; -use middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; -use std::iter::once; -use syntax::ast; -use syntax::codemap::Span; -use util::common::ErrorReported; - -/// Returns the set of obligations needed to make `ty` well-formed. -/// If `ty` contains unresolved inference variables, this may include -/// further WF obligations. However, if `ty` IS an unresolved -/// inference variable, returns `None`, because we are not able to -/// make any progress at all. This is to prevent "livelock" where we -/// say "$0 is WF if $0 is WF". -pub fn obligations<'a,'tcx>(infcx: &InferCtxt<'a, 'tcx>, - body_id: ast::NodeId, - ty: Ty<'tcx>, - span: Span) - -> Option>> -{ - let mut wf = WfPredicates { infcx: infcx, - body_id: body_id, - span: span, - out: vec![] }; - if wf.compute(ty) { - debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out); - let result = wf.normalize(); - debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", ty, body_id, result); - Some(result) - } else { - None // no progress made, return None - } -} - -/// Returns the obligations that make this trait reference -/// well-formed. For example, if there is a trait `Set` defined like -/// `trait Set`, then the trait reference `Foo: Set` is WF -/// if `Bar: Eq`. -pub fn trait_obligations<'a,'tcx>(infcx: &InferCtxt<'a, 'tcx>, - body_id: ast::NodeId, - trait_ref: &ty::TraitRef<'tcx>, - span: Span) - -> Vec> -{ - let mut wf = WfPredicates { infcx: infcx, body_id: body_id, span: span, out: vec![] }; - wf.compute_trait_ref(trait_ref); - wf.normalize() -} - -pub fn predicate_obligations<'a,'tcx>(infcx: &InferCtxt<'a, 'tcx>, - body_id: ast::NodeId, - predicate: &ty::Predicate<'tcx>, - span: Span) - -> Vec> -{ - let mut wf = WfPredicates { infcx: infcx, body_id: body_id, span: span, out: vec![] }; - - // (*) ok to skip binders, because wf code is prepared for it - match *predicate { - ty::Predicate::Trait(ref t) => { - wf.compute_trait_ref(&t.skip_binder().trait_ref); // (*) - } - ty::Predicate::Equate(ref t) => { - wf.compute(t.skip_binder().0); - wf.compute(t.skip_binder().1); - } - ty::Predicate::RegionOutlives(..) => { - } - ty::Predicate::TypeOutlives(ref t) => { - wf.compute(t.skip_binder().0); - } - ty::Predicate::Projection(ref t) => { - let t = t.skip_binder(); // (*) - wf.compute_projection(t.projection_ty); - wf.compute(t.ty); - } - ty::Predicate::WellFormed(t) => { - wf.compute(t); - } - ty::Predicate::ObjectSafe(_) => { - } - } - - wf.normalize() -} - -/// Implied bounds are region relationships that we deduce -/// automatically. The idea is that (e.g.) a caller must check that a -/// function's argument types are well-formed immediately before -/// calling that fn, and hence the *callee* can assume that its -/// argument types are well-formed. This may imply certain relationships -/// between generic parameters. For example: -/// -/// fn foo<'a,T>(x: &'a T) -/// -/// can only be called with a `'a` and `T` such that `&'a T` is WF. -/// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`. -#[derive(Debug)] -pub enum ImpliedBound<'tcx> { - RegionSubRegion(ty::Region, ty::Region), - RegionSubParam(ty::Region, ty::ParamTy), - RegionSubProjection(ty::Region, ty::ProjectionTy<'tcx>), -} - -/// Compute the implied bounds that a callee/impl can assume based on -/// the fact that caller/projector has ensured that `ty` is WF. See -/// the `ImpliedBound` type for more details. -pub fn implied_bounds<'a,'tcx>( - infcx: &'a InferCtxt<'a,'tcx>, - body_id: ast::NodeId, - ty: Ty<'tcx>, - span: Span) - -> Vec> -{ - // Sometimes when we ask what it takes for T: WF, we get back that - // U: WF is required; in that case, we push U onto this stack and - // process it next. Currently (at least) these resulting - // predicates are always guaranteed to be a subset of the original - // type, so we need not fear non-termination. - let mut wf_types = vec![ty]; - - let mut implied_bounds = vec![]; - - while let Some(ty) = wf_types.pop() { - // Compute the obligations for `ty` to be well-formed. If `ty` is - // an unresolved inference variable, just substituted an empty set - // -- because the return type here is going to be things we *add* - // to the environment, it's always ok for this set to be smaller - // than the ultimate set. (Note: normally there won't be - // unresolved inference variables here anyway, but there might be - // during typeck under some circumstances.) - let obligations = obligations(infcx, body_id, ty, span).unwrap_or(vec![]); - - // From the full set of obligations, just filter down to the - // region relationships. - implied_bounds.extend( - obligations - .into_iter() - .flat_map(|obligation| { - assert!(!obligation.has_escaping_regions()); - match obligation.predicate { - ty::Predicate::Trait(..) | - ty::Predicate::Equate(..) | - ty::Predicate::Projection(..) | - ty::Predicate::ObjectSafe(..) => - vec![], - - ty::Predicate::WellFormed(subty) => { - wf_types.push(subty); - vec![] - } - - ty::Predicate::RegionOutlives(ref data) => - match infcx.tcx.no_late_bound_regions(data) { - None => - vec![], - Some(ty::OutlivesPredicate(r_a, r_b)) => - vec![ImpliedBound::RegionSubRegion(r_b, r_a)], - }, - - ty::Predicate::TypeOutlives(ref data) => - match infcx.tcx.no_late_bound_regions(data) { - None => vec![], - Some(ty::OutlivesPredicate(ty_a, r_b)) => { - let components = outlives::components(infcx, ty_a); - implied_bounds_from_components(r_b, components) - } - }, - }})); - } - - implied_bounds -} - -/// When we have an implied bound that `T: 'a`, we can further break -/// this down to determine what relationships would have to hold for -/// `T: 'a` to hold. We get to assume that the caller has validated -/// those relationships. -fn implied_bounds_from_components<'tcx>(sub_region: ty::Region, - sup_components: Vec>) - -> Vec> -{ - sup_components - .into_iter() - .flat_map(|component| { - match component { - Component::Region(r) => - vec!(ImpliedBound::RegionSubRegion(sub_region, r)), - Component::Param(p) => - vec!(ImpliedBound::RegionSubParam(sub_region, p)), - Component::Projection(p) => - vec!(ImpliedBound::RegionSubProjection(sub_region, p)), - Component::EscapingProjection(_) => - // If the projection has escaping regions, don't - // try to infer any implied bounds even for its - // free components. This is conservative, because - // the caller will still have to prove that those - // free components outlive `sub_region`. But the - // idea is that the WAY that the caller proves - // that may change in the future and we want to - // give ourselves room to get smarter here. - vec!(), - Component::UnresolvedInferenceVariable(..) => - vec!(), - } - }) - .collect() -} - -struct WfPredicates<'a,'tcx:'a> { - infcx: &'a InferCtxt<'a, 'tcx>, - body_id: ast::NodeId, - span: Span, - out: Vec>, -} - -impl<'a,'tcx> WfPredicates<'a,'tcx> { - fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> { - traits::ObligationCause::new(self.span, self.body_id, code) - } - - fn normalize(&mut self) -> Vec> { - let cause = self.cause(traits::MiscObligation); - let infcx = &mut self.infcx; - self.out.iter() - .inspect(|pred| assert!(!pred.has_escaping_regions())) - .flat_map(|pred| { - let mut selcx = traits::SelectionContext::new(infcx); - let pred = traits::normalize(&mut selcx, cause.clone(), pred); - once(pred.value).chain(pred.obligations) - }) - .collect() - } - - /// Pushes the obligations required for `trait_ref` to be WF into - /// `self.out`. - fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>) { - let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs); - self.out.extend(obligations); - - let cause = self.cause(traits::MiscObligation); - self.out.extend( - trait_ref.substs.types - .as_slice() - .iter() - .filter(|ty| !ty.has_escaping_regions()) - .map(|ty| traits::Obligation::new(cause.clone(), - ty::Predicate::WellFormed(ty)))); - } - - /// Pushes the obligations required for `trait_ref::Item` to be WF - /// into `self.out`. - fn compute_projection(&mut self, data: ty::ProjectionTy<'tcx>) { - // A projection is well-formed if (a) the trait ref itself is - // WF WF and (b) the trait-ref holds. (It may also be - // normalizable and be WF that way.) - - self.compute_trait_ref(&data.trait_ref); - - if !data.has_escaping_regions() { - let predicate = data.trait_ref.to_predicate(); - let cause = self.cause(traits::ProjectionWf(data)); - self.out.push(traits::Obligation::new(cause, predicate)); - } - } - - /// Push new obligations into `out`. Returns true if it was able - /// to generate all the predicates needed to validate that `ty0` - /// is WF. Returns false if `ty0` is an unresolved type variable, - /// in which case we are not able to simplify at all. - fn compute(&mut self, ty0: Ty<'tcx>) -> bool { - let mut subtys = ty0.walk(); - while let Some(ty) = subtys.next() { - match ty.sty { - ty::TyBool | - ty::TyChar | - ty::TyInt(..) | - ty::TyUint(..) | - ty::TyFloat(..) | - ty::TyError | - ty::TyStr | - ty::TyParam(_) => { - // WfScalar, WfParameter, etc - } - - ty::TySlice(subty) | - ty::TyArray(subty, _) => { - if !subty.has_escaping_regions() { - let cause = self.cause(traits::SliceOrArrayElem); - match traits::trait_ref_for_builtin_bound(self.infcx.tcx, - ty::BoundSized, - subty) { - Ok(trait_ref) => { - self.out.push( - traits::Obligation::new(cause, - trait_ref.to_predicate())); - } - Err(ErrorReported) => { } - } - } - } - - ty::TyBox(_) | - ty::TyTuple(_) | - ty::TyRawPtr(_) => { - // simple cases that are WF if their type args are WF - } - - ty::TyProjection(data) => { - subtys.skip_current_subtree(); // subtree handled by compute_projection - self.compute_projection(data); - } - - ty::TyEnum(def, substs) | - ty::TyStruct(def, substs) => { - // WfNominalType - let obligations = self.nominal_obligations(def.did, substs); - self.out.extend(obligations); - } - - ty::TyRef(r, mt) => { - // WfReference - if !r.has_escaping_regions() && !mt.ty.has_escaping_regions() { - let cause = self.cause(traits::ReferenceOutlivesReferent(ty)); - self.out.push( - traits::Obligation::new( - cause, - ty::Predicate::TypeOutlives( - ty::Binder( - ty::OutlivesPredicate(mt.ty, *r))))); - } - } - - ty::TyClosure(..) => { - // the types in a closure are always the types of - // local variables (or possibly references to local - // variables), we'll walk those. - // - // (Though, local variables are probably not - // needed, as they are separately checked w/r/t - // WFedness.) - } - - ty::TyFnDef(..) | ty::TyFnPtr(_) => { - // let the loop iterate into the argument/return - // types appearing in the fn signature - } - - ty::TyTrait(ref data) => { - // WfObject - // - // Here, we defer WF checking due to higher-ranked - // regions. This is perhaps not ideal. - self.from_object_ty(ty, data); - - // FIXME(#27579) RFC also considers adding trait - // obligations that don't refer to Self and - // checking those - - let cause = self.cause(traits::MiscObligation); - self.out.push( - traits::Obligation::new( - cause, - ty::Predicate::ObjectSafe(data.principal_def_id()))); - } - - // Inference variables are the complicated case, since we don't - // know what type they are. We do two things: - // - // 1. Check if they have been resolved, and if so proceed with - // THAT type. - // 2. If not, check whether this is the type that we - // started with (ty0). In that case, we've made no - // progress at all, so return false. Otherwise, - // we've at least simplified things (i.e., we went - // from `Vec<$0>: WF` to `$0: WF`, so we can - // register a pending obligation and keep - // moving. (Goal is that an "inductive hypothesis" - // is satisfied to ensure termination.) - ty::TyInfer(_) => { - let ty = self.infcx.shallow_resolve(ty); - if let ty::TyInfer(_) = ty.sty { // not yet resolved... - if ty == ty0 { // ...this is the type we started from! no progress. - return false; - } - - let cause = self.cause(traits::MiscObligation); - self.out.push( // ...not the type we started from, so we made progress. - traits::Obligation::new(cause, ty::Predicate::WellFormed(ty))); - } else { - // Yes, resolved, proceed with the - // result. Should never return false because - // `ty` is not a TyInfer. - assert!(self.compute(ty)); - } - } - } - } - - // if we made it through that loop above, we made progress! - return true; - } - - fn nominal_obligations(&mut self, - def_id: DefId, - substs: &Substs<'tcx>) - -> Vec> - { - let predicates = - self.infcx.tcx.lookup_predicates(def_id) - .instantiate(self.infcx.tcx, substs); - let cause = self.cause(traits::ItemObligation(def_id)); - predicates.predicates - .into_iter() - .map(|pred| traits::Obligation::new(cause.clone(), pred)) - .filter(|pred| !pred.has_escaping_regions()) - .collect() - } - - fn from_object_ty(&mut self, ty: Ty<'tcx>, data: &ty::TraitTy<'tcx>) { - // Imagine a type like this: - // - // trait Foo { } - // trait Bar<'c> : 'c { } - // - // &'b (Foo+'c+Bar<'d>) - // ^ - // - // In this case, the following relationships must hold: - // - // 'b <= 'c - // 'd <= 'c - // - // The first conditions is due to the normal region pointer - // rules, which say that a reference cannot outlive its - // referent. - // - // The final condition may be a bit surprising. In particular, - // you may expect that it would have been `'c <= 'd`, since - // usually lifetimes of outer things are conservative - // approximations for inner things. However, it works somewhat - // differently with trait objects: here the idea is that if the - // user specifies a region bound (`'c`, in this case) it is the - // "master bound" that *implies* that bounds from other traits are - // all met. (Remember that *all bounds* in a type like - // `Foo+Bar+Zed` must be met, not just one, hence if we write - // `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and - // 'y.) - // - // Note: in fact we only permit builtin traits, not `Bar<'d>`, I - // am looking forward to the future here. - - if !data.has_escaping_regions() { - let implicit_bounds = - object_region_bounds(self.infcx.tcx, - &data.principal, - data.bounds.builtin_bounds); - - let explicit_bound = data.bounds.region_bound; - - for implicit_bound in implicit_bounds { - let cause = self.cause(traits::ReferenceOutlivesReferent(ty)); - let outlives = ty::Binder(ty::OutlivesPredicate(explicit_bound, implicit_bound)); - self.out.push(traits::Obligation::new(cause, outlives.to_predicate())); - } - } - } -} - -/// Given an object type like `SomeTrait+Send`, computes the lifetime -/// bounds that must hold on the elided self type. These are derived -/// from the declarations of `SomeTrait`, `Send`, and friends -- if -/// they declare `trait SomeTrait : 'static`, for example, then -/// `'static` would appear in the list. The hard work is done by -/// `ty::required_region_bounds`, see that for more information. -pub fn object_region_bounds<'tcx>( - tcx: &TyCtxt<'tcx>, - principal: &ty::PolyTraitRef<'tcx>, - others: ty::BuiltinBounds) - -> Vec -{ - // Since we don't actually *know* the self type for an object, - // this "open(err)" serves as a kind of dummy standin -- basically - // a skolemized type. - let open_ty = tcx.mk_infer(ty::FreshTy(0)); - - // Note that we preserve the overall binding levels here. - assert!(!open_ty.has_escaping_regions()); - let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty)); - let trait_refs = vec!(ty::Binder(ty::TraitRef::new(principal.0.def_id, substs))); - - let mut predicates = others.to_predicates(tcx, open_ty); - predicates.extend(trait_refs.iter().map(|t| t.to_predicate())); - - tcx.required_region_bounds(open_ty, predicates) -} diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index 20cf6d929ca..b9073810783 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -12,8 +12,8 @@ use graphviz::IntoCow; use middle::const_eval::ConstVal; use rustc_const_eval::{ConstUsize, ConstInt}; use middle::def_id::DefId; -use middle::ty::subst::Substs; -use middle::ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty}; +use ty::subst::Substs; +use ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty}; use util::ppaux; use rustc_back::slice; use rustc_front::hir::InlineAsm; diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 0c9e00a6c5e..46d99dbef8c 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -14,9 +14,9 @@ */ use mir::repr::*; -use middle::ty::subst::{Subst, Substs}; -use middle::ty::{self, AdtDef, Ty, TyCtxt}; -use middle::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; +use ty::subst::{Subst, Substs}; +use ty::{self, AdtDef, Ty, TyCtxt}; +use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use rustc_front::hir; #[derive(Copy, Clone, Debug)] diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index afcb5b95631..410e3f9d066 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -10,7 +10,7 @@ use mir::mir_map::MirMap; use mir::repr::Mir; -use middle::ty::TyCtxt; +use ty::TyCtxt; use syntax::ast::NodeId; /// Various information about pass. diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 8c180ecb233..856902bea3c 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -10,8 +10,8 @@ use middle::const_eval::ConstVal; use middle::def_id::DefId; -use middle::subst::Substs; -use middle::ty::{ClosureSubsts, FnOutput, Region, Ty}; +use ty::subst::Substs; +use ty::{ClosureSubsts, FnOutput, Region, Ty}; use mir::repr::*; use rustc_const_eval::ConstUsize; use rustc_data_structures::tuple_slice::TupleSlice; diff --git a/src/librustc/traits/README.md b/src/librustc/traits/README.md new file mode 100644 index 00000000000..ff72f9dd07e --- /dev/null +++ b/src/librustc/traits/README.md @@ -0,0 +1,470 @@ +# TRAIT RESOLUTION + +This document describes the general process and points out some non-obvious +things. + +## Major concepts + +Trait resolution is the process of pairing up an impl with each +reference to a trait. So, for example, if there is a generic function like: + + fn clone_slice(x: &[T]) -> Vec { ... } + +and then a call to that function: + + let v: Vec = clone_slice([1, 2, 3]) + +it is the job of trait resolution to figure out (in which case) +whether there exists an impl of `isize : Clone` + +Note that in some cases, like generic functions, we may not be able to +find a specific impl, but we can figure out that the caller must +provide an impl. To see what I mean, consider the body of `clone_slice`: + + fn clone_slice(x: &[T]) -> Vec { + let mut v = Vec::new(); + for e in &x { + v.push((*e).clone()); // (*) + } + } + +The line marked `(*)` is only legal if `T` (the type of `*e`) +implements the `Clone` trait. Naturally, since we don't know what `T` +is, we can't find the specific impl; but based on the bound `T:Clone`, +we can say that there exists an impl which the caller must provide. + +We use the term *obligation* to refer to a trait reference in need of +an impl. + +## Overview + +Trait resolution consists of three major parts: + +- SELECTION: Deciding how to resolve a specific obligation. For + example, selection might decide that a specific obligation can be + resolved by employing an impl which matches the self type, or by + using a parameter bound. In the case of an impl, Selecting one + obligation can create *nested obligations* because of where clauses + on the impl itself. It may also require evaluating those nested + obligations to resolve ambiguities. + +- FULFILLMENT: The fulfillment code is what tracks that obligations + are completely fulfilled. Basically it is a worklist of obligations + to be selected: once selection is successful, the obligation is + removed from the worklist and any nested obligations are enqueued. + +- COHERENCE: The coherence checks are intended to ensure that there + are never overlapping impls, where two impls could be used with + equal precedence. + +## Selection + +Selection is the process of deciding whether an obligation can be +resolved and, if so, how it is to be resolved (via impl, where clause, etc). +The main interface is the `select()` function, which takes an obligation +and returns a `SelectionResult`. There are three possible outcomes: + +- `Ok(Some(selection))` -- yes, the obligation can be resolved, and + `selection` indicates how. If the impl was resolved via an impl, + then `selection` may also indicate nested obligations that are required + by the impl. + +- `Ok(None)` -- we are not yet sure whether the obligation can be + resolved or not. This happens most commonly when the obligation + contains unbound type variables. + +- `Err(err)` -- the obligation definitely cannot be resolved due to a + type error, or because there are no impls that could possibly apply, + etc. + +The basic algorithm for selection is broken into two big phases: +candidate assembly and confirmation. + +### Candidate assembly + +Searches for impls/where-clauses/etc that might +possibly be used to satisfy the obligation. Each of those is called +a candidate. To avoid ambiguity, we want to find exactly one +candidate that is definitively applicable. In some cases, we may not +know whether an impl/where-clause applies or not -- this occurs when +the obligation contains unbound inference variables. + +The basic idea for candidate assembly is to do a first pass in which +we identify all possible candidates. During this pass, all that we do +is try and unify the type parameters. (In particular, we ignore any +nested where clauses.) Presuming that this unification succeeds, the +impl is added as a candidate. + +Once this first pass is done, we can examine the set of candidates. If +it is a singleton set, then we are done: this is the only impl in +scope that could possibly apply. Otherwise, we can winnow down the set +of candidates by using where clauses and other conditions. If this +reduced set yields a single, unambiguous entry, we're good to go, +otherwise the result is considered ambiguous. + +#### The basic process: Inferring based on the impls we see + +This process is easier if we work through some examples. Consider +the following trait: + +``` +trait Convert { + fn convert(&self) -> Target; +} +``` + +This trait just has one method. It's about as simple as it gets. It +converts from the (implicit) `Self` type to the `Target` type. If we +wanted to permit conversion between `isize` and `usize`, we might +implement `Convert` like so: + +```rust +impl Convert for isize { ... } // isize -> usize +impl Convert for usize { ... } // usize -> isize +``` + +Now imagine there is some code like the following: + +```rust +let x: isize = ...; +let y = x.convert(); +``` + +The call to convert will generate a trait reference `Convert<$Y> for +isize`, where `$Y` is the type variable representing the type of +`y`. When we match this against the two impls we can see, we will find +that only one remains: `Convert for isize`. Therefore, we can +select this impl, which will cause the type of `$Y` to be unified to +`usize`. (Note that while assembling candidates, we do the initial +unifications in a transaction, so that they don't affect one another.) + +There are tests to this effect in src/test/run-pass: + + traits-multidispatch-infer-convert-source-and-target.rs + traits-multidispatch-infer-convert-target.rs + +#### Winnowing: Resolving ambiguities + +But what happens if there are multiple impls where all the types +unify? Consider this example: + +```rust +trait Get { + fn get(&self) -> Self; +} + +impl Get for T { + fn get(&self) -> T { *self } +} + +impl Get for Box { + fn get(&self) -> Box { box get_it(&**self) } +} +``` + +What happens when we invoke `get_it(&box 1_u16)`, for example? In this +case, the `Self` type is `Box` -- that unifies with both impls, +because the first applies to all types, and the second to all +boxes. In the olden days we'd have called this ambiguous. But what we +do now is do a second *winnowing* pass that considers where clauses +and attempts to remove candidates -- in this case, the first impl only +applies if `Box : Copy`, which doesn't hold. After winnowing, +then, we are left with just one candidate, so we can proceed. There is +a test of this in `src/test/run-pass/traits-conditional-dispatch.rs`. + +#### Matching + +The subroutines that decide whether a particular impl/where-clause/etc +applies to a particular obligation. At the moment, this amounts to +unifying the self types, but in the future we may also recursively +consider some of the nested obligations, in the case of an impl. + +#### Lifetimes and selection + +Because of how that lifetime inference works, it is not possible to +give back immediate feedback as to whether a unification or subtype +relationship between lifetimes holds or not. Therefore, lifetime +matching is *not* considered during selection. This is reflected in +the fact that subregion assignment is infallible. This may yield +lifetime constraints that will later be found to be in error (in +contrast, the non-lifetime-constraints have already been checked +during selection and can never cause an error, though naturally they +may lead to other errors downstream). + +#### Where clauses + +Besides an impl, the other major way to resolve an obligation is via a +where clause. The selection process is always given a *parameter +environment* which contains a list of where clauses, which are +basically obligations that can assume are satisfiable. We will iterate +over that list and check whether our current obligation can be found +in that list, and if so it is considered satisfied. More precisely, we +want to check whether there is a where-clause obligation that is for +the same trait (or some subtrait) and for which the self types match, +using the definition of *matching* given above. + +Consider this simple example: + + trait A1 { ... } + trait A2 : A1 { ... } + + trait B { ... } + + fn foo { ... } + +Clearly we can use methods offered by `A1`, `A2`, or `B` within the +body of `foo`. In each case, that will incur an obligation like `X : +A1` or `X : A2`. The parameter environment will contain two +where-clauses, `X : A2` and `X : B`. For each obligation, then, we +search this list of where-clauses. To resolve an obligation `X:A1`, +we would note that `X:A2` implies that `X:A1`. + +### Confirmation + +Confirmation unifies the output type parameters of the trait with the +values found in the obligation, possibly yielding a type error. If we +return to our example of the `Convert` trait from the previous +section, confirmation is where an error would be reported, because the +impl specified that `T` would be `usize`, but the obligation reported +`char`. Hence the result of selection would be an error. + +### Selection during translation + +During type checking, we do not store the results of trait selection. +We simply wish to verify that trait selection will succeed. Then +later, at trans time, when we have all concrete types available, we +can repeat the trait selection. In this case, we do not consider any +where-clauses to be in scope. We know that therefore each resolution +will resolve to a particular impl. + +One interesting twist has to do with nested obligations. In general, in trans, +we only need to do a "shallow" selection for an obligation. That is, we wish to +identify which impl applies, but we do not (yet) need to decide how to select +any nested obligations. Nonetheless, we *do* currently do a complete resolution, +and that is because it can sometimes inform the results of type inference. That is, +we do not have the full substitutions in terms of the type variables of the impl available +to us, so we must run trait selection to figure everything out. + +Here is an example: + + trait Foo { ... } + impl> Foo for Vec { ... } + + impl Bar for isize { ... } + +After one shallow round of selection for an obligation like `Vec +: Foo`, we would know which impl we want, and we would know that +`T=isize`, but we do not know the type of `U`. We must select the +nested obligation `isize : Bar` to find out that `U=usize`. + +It would be good to only do *just as much* nested resolution as +necessary. Currently, though, we just do a full resolution. + +# Higher-ranked trait bounds + +One of the more subtle concepts at work are *higher-ranked trait +bounds*. An example of such a bound is `for<'a> MyTrait<&'a isize>`. +Let's walk through how selection on higher-ranked trait references +works. + +## Basic matching and skolemization leaks + +Let's walk through the test `compile-fail/hrtb-just-for-static.rs` to see +how it works. The test starts with the trait `Foo`: + +```rust +trait Foo { + fn foo(&self, x: X) { } +} +``` + +Let's say we have a function `want_hrtb` that wants a type which +implements `Foo<&'a isize>` for any `'a`: + +```rust +fn want_hrtb() where T : for<'a> Foo<&'a isize> { ... } +``` + +Now we have a struct `AnyInt` that implements `Foo<&'a isize>` for any +`'a`: + +```rust +struct AnyInt; +impl<'a> Foo<&'a isize> for AnyInt { } +``` + +And the question is, does `AnyInt : for<'a> Foo<&'a isize>`? We want the +answer to be yes. The algorithm for figuring it out is closely related +to the subtyping for higher-ranked types (which is described in +`middle::infer::higher_ranked::doc`, but also in a [paper by SPJ] that +I recommend you read). + +1. Skolemize the obligation. +2. Match the impl against the skolemized obligation. +3. Check for skolemization leaks. + +[paper by SPJ]: http://research.microsoft.com/en-us/um/people/simonpj/papers/higher-rank/ + +So let's work through our example. The first thing we would do is to +skolemize the obligation, yielding `AnyInt : Foo<&'0 isize>` (here `'0` +represents skolemized region #0). Note that now have no quantifiers; +in terms of the compiler type, this changes from a `ty::PolyTraitRef` +to a `TraitRef`. We would then create the `TraitRef` from the impl, +using fresh variables for it's bound regions (and thus getting +`Foo<&'$a isize>`, where `'$a` is the inference variable for `'a`). Next +we relate the two trait refs, yielding a graph with the constraint +that `'0 == '$a`. Finally, we check for skolemization "leaks" -- a +leak is basically any attempt to relate a skolemized region to another +skolemized region, or to any region that pre-existed the impl match. +The leak check is done by searching from the skolemized region to find +the set of regions that it is related to in any way. This is called +the "taint" set. To pass the check, that set must consist *solely* of +itself and region variables from the impl. If the taint set includes +any other region, then the match is a failure. In this case, the taint +set for `'0` is `{'0, '$a}`, and hence the check will succeed. + +Let's consider a failure case. Imagine we also have a struct + +```rust +struct StaticInt; +impl Foo<&'static isize> for StaticInt; +``` + +We want the obligation `StaticInt : for<'a> Foo<&'a isize>` to be +considered unsatisfied. The check begins just as before. `'a` is +skolemized to `'0` and the impl trait reference is instantiated to +`Foo<&'static isize>`. When we relate those two, we get a constraint +like `'static == '0`. This means that the taint set for `'0` is `{'0, +'static}`, which fails the leak check. + +## Higher-ranked trait obligations + +Once the basic matching is done, we get to another interesting topic: +how to deal with impl obligations. I'll work through a simple example +here. Imagine we have the traits `Foo` and `Bar` and an associated impl: + +``` +trait Foo { + fn foo(&self, x: X) { } +} + +trait Bar { + fn bar(&self, x: X) { } +} + +impl Foo for F + where F : Bar +{ +} +``` + +Now let's say we have a obligation `for<'a> Foo<&'a isize>` and we match +this impl. What obligation is generated as a result? We want to get +`for<'a> Bar<&'a isize>`, but how does that happen? + +After the matching, we are in a position where we have a skolemized +substitution like `X => &'0 isize`. If we apply this substitution to the +impl obligations, we get `F : Bar<&'0 isize>`. Obviously this is not +directly usable because the skolemized region `'0` cannot leak out of +our computation. + +What we do is to create an inverse mapping from the taint set of `'0` +back to the original bound region (`'a`, here) that `'0` resulted +from. (This is done in `higher_ranked::plug_leaks`). We know that the +leak check passed, so this taint set consists solely of the skolemized +region itself plus various intermediate region variables. We then walk +the trait-reference and convert every region in that taint set back to +a late-bound region, so in this case we'd wind up with `for<'a> F : +Bar<&'a isize>`. + +# Caching and subtle considerations therewith + +In general we attempt to cache the results of trait selection. This +is a somewhat complex process. Part of the reason for this is that we +want to be able to cache results even when all the types in the trait +reference are not fully known. In that case, it may happen that the +trait selection process is also influencing type variables, so we have +to be able to not only cache the *result* of the selection process, +but *replay* its effects on the type variables. + +## An example + +The high-level idea of how the cache works is that we first replace +all unbound inference variables with skolemized versions. Therefore, +if we had a trait reference `usize : Foo<$1>`, where `$n` is an unbound +inference variable, we might replace it with `usize : Foo<%0>`, where +`%n` is a skolemized type. We would then look this up in the cache. +If we found a hit, the hit would tell us the immediate next step to +take in the selection process: i.e., apply impl #22, or apply where +clause `X : Foo`. Let's say in this case there is no hit. +Therefore, we search through impls and where clauses and so forth, and +we come to the conclusion that the only possible impl is this one, +with def-id 22: + + impl Foo for usize { ... } // Impl #22 + +We would then record in the cache `usize : Foo<%0> ==> +ImplCandidate(22)`. Next we would confirm `ImplCandidate(22)`, which +would (as a side-effect) unify `$1` with `isize`. + +Now, at some later time, we might come along and see a `usize : +Foo<$3>`. When skolemized, this would yield `usize : Foo<%0>`, just as +before, and hence the cache lookup would succeed, yielding +`ImplCandidate(22)`. We would confirm `ImplCandidate(22)` which would +(as a side-effect) unify `$3` with `isize`. + +## Where clauses and the local vs global cache + +One subtle interaction is that the results of trait lookup will vary +depending on what where clauses are in scope. Therefore, we actually +have *two* caches, a local and a global cache. The local cache is +attached to the `ParameterEnvironment` and the global cache attached +to the `tcx`. We use the local cache whenever the result might depend +on the where clauses that are in scope. The determination of which +cache to use is done by the method `pick_candidate_cache` in +`select.rs`. At the moment, we use a very simple, conservative rule: +if there are any where-clauses in scope, then we use the local cache. +We used to try and draw finer-grained distinctions, but that led to a +serious of annoying and weird bugs like #22019 and #18290. This simple +rule seems to be pretty clearly safe and also still retains a very +high hit rate (~95% when compiling rustc). + +# Specialization + +Defined in the `specialize` module. + +The basic strategy is to build up a *specialization graph* during +coherence checking. Insertion into the graph locates the right place +to put an impl in the specialization hierarchy; if there is no right +place (due to partial overlap but no containment), you get an overlap +error. Specialization is consulted when selecting an impl (of course), +and the graph is consulted when propagating defaults down the +specialization hierarchy. + +You might expect that the specialization graph would be used during +selection -- i.e., when actually performing specialization. This is +not done for two reasons: + +- It's merely an optimization: given a set of candidates that apply, + we can determine the most specialized one by comparing them directly + for specialization, rather than consulting the graph. Given that we + also cache the results of selection, the benefit of this + optimization is questionable. + +- To build the specialization graph in the first place, we need to use + selection (because we need to determine whether one impl specializes + another). Dealing with this reentrancy would require some additional + mode switch for selection. Given that there seems to be no strong + reason to use the graph anyway, we stick with a simpler approach in + selection, and use the graph only for propagating default + implementations. + +Trait impl selection can succeed even when multiple impls can apply, +as long as they are part of the same specialization family. In that +case, it returns a *single* impl on success -- this is the most +specialized impl *known* to apply. However, if there are any inference +variables in play, the returned impl may not be the actual impl we +will use at trans time. Thus, we take special care to avoid projecting +associated types unless either (1) the associated type does not use +`default` and thus cannot be overridden or (2) all input types are +known concretely. diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs new file mode 100644 index 00000000000..b5b5da62080 --- /dev/null +++ b/src/librustc/traits/coherence.rs @@ -0,0 +1,299 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! See `README.md` for high-level documentation + +use super::{SelectionContext, Obligation, ObligationCause}; + +use middle::cstore::LOCAL_CRATE; +use middle::def_id::DefId; +use ty::subst::TypeSpace; +use ty::{self, Ty, TyCtxt}; +use infer::{self, InferCtxt, TypeOrigin}; +use syntax::codemap::DUMMY_SP; + +#[derive(Copy, Clone)] +struct InferIsLocal(bool); + +/// If there are types that satisfy both impls, returns a suitably-freshened +/// `ImplHeader` with those types substituted +pub fn overlapping_impls<'cx, 'tcx>(infcx: &InferCtxt<'cx, 'tcx>, + impl1_def_id: DefId, + impl2_def_id: DefId) + -> Option> +{ + debug!("impl_can_satisfy(\ + impl1_def_id={:?}, \ + impl2_def_id={:?})", + impl1_def_id, + impl2_def_id); + + let selcx = &mut SelectionContext::intercrate(infcx); + overlap(selcx, impl1_def_id, impl2_def_id) +} + +/// Can both impl `a` and impl `b` be satisfied by a common type (including +/// `where` clauses)? If so, returns an `ImplHeader` that unifies the two impls. +fn overlap<'cx, 'tcx>(selcx: &mut SelectionContext<'cx, 'tcx>, + a_def_id: DefId, + b_def_id: DefId) + -> Option> +{ + debug!("overlap(a_def_id={:?}, b_def_id={:?})", + a_def_id, + b_def_id); + + let a_impl_header = ty::ImplHeader::with_fresh_ty_vars(selcx, a_def_id); + let b_impl_header = ty::ImplHeader::with_fresh_ty_vars(selcx, b_def_id); + + debug!("overlap: a_impl_header={:?}", a_impl_header); + debug!("overlap: b_impl_header={:?}", b_impl_header); + + // Do `a` and `b` unify? If not, no overlap. + if let Err(_) = infer::mk_eq_impl_headers(selcx.infcx(), + true, + TypeOrigin::Misc(DUMMY_SP), + &a_impl_header, + &b_impl_header) { + return None; + } + + debug!("overlap: unification check succeeded"); + + // Are any of the obligations unsatisfiable? If so, no overlap. + let infcx = selcx.infcx(); + let opt_failing_obligation = + a_impl_header.predicates + .iter() + .chain(&b_impl_header.predicates) + .map(|p| infcx.resolve_type_vars_if_possible(p)) + .map(|p| Obligation { cause: ObligationCause::dummy(), + recursion_depth: 0, + predicate: p }) + .find(|o| !selcx.evaluate_obligation(o)); + + if let Some(failing_obligation) = opt_failing_obligation { + debug!("overlap: obligation unsatisfiable {:?}", failing_obligation); + return None + } + + Some(selcx.infcx().resolve_type_vars_if_possible(&a_impl_header)) +} + +pub fn trait_ref_is_knowable<'tcx>(tcx: &TyCtxt<'tcx>, trait_ref: &ty::TraitRef<'tcx>) -> bool +{ + debug!("trait_ref_is_knowable(trait_ref={:?})", trait_ref); + + // if the orphan rules pass, that means that no ancestor crate can + // impl this, so it's up to us. + if orphan_check_trait_ref(tcx, trait_ref, InferIsLocal(false)).is_ok() { + debug!("trait_ref_is_knowable: orphan check passed"); + return true; + } + + // if the trait is not marked fundamental, then it's always possible that + // an ancestor crate will impl this in the future, if they haven't + // already + if + trait_ref.def_id.krate != LOCAL_CRATE && + !tcx.has_attr(trait_ref.def_id, "fundamental") + { + debug!("trait_ref_is_knowable: trait is neither local nor fundamental"); + return false; + } + + // find out when some downstream (or cousin) crate could impl this + // trait-ref, presuming that all the parameters were instantiated + // with downstream types. If not, then it could only be + // implemented by an upstream crate, which means that the impl + // must be visible to us, and -- since the trait is fundamental + // -- we can test. + orphan_check_trait_ref(tcx, trait_ref, InferIsLocal(true)).is_err() +} + +pub enum OrphanCheckErr<'tcx> { + NoLocalInputType, + UncoveredTy(Ty<'tcx>), +} + +/// Checks the coherence orphan rules. `impl_def_id` should be the +/// def-id of a trait impl. To pass, either the trait must be local, or else +/// two conditions must be satisfied: +/// +/// 1. All type parameters in `Self` must be "covered" by some local type constructor. +/// 2. Some local type must appear in `Self`. +pub fn orphan_check<'tcx>(tcx: &TyCtxt<'tcx>, + impl_def_id: DefId) + -> Result<(), OrphanCheckErr<'tcx>> +{ + debug!("orphan_check({:?})", impl_def_id); + + // We only except this routine to be invoked on implementations + // of a trait, not inherent implementations. + let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); + debug!("orphan_check: trait_ref={:?}", trait_ref); + + // If the *trait* is local to the crate, ok. + if trait_ref.def_id.is_local() { + debug!("trait {:?} is local to current crate", + trait_ref.def_id); + return Ok(()); + } + + orphan_check_trait_ref(tcx, &trait_ref, InferIsLocal(false)) +} + +fn orphan_check_trait_ref<'tcx>(tcx: &TyCtxt<'tcx>, + trait_ref: &ty::TraitRef<'tcx>, + infer_is_local: InferIsLocal) + -> Result<(), OrphanCheckErr<'tcx>> +{ + debug!("orphan_check_trait_ref(trait_ref={:?}, infer_is_local={})", + trait_ref, infer_is_local.0); + + // First, create an ordered iterator over all the type parameters to the trait, with the self + // type appearing first. + let input_tys = Some(trait_ref.self_ty()); + let input_tys = input_tys.iter().chain(trait_ref.substs.types.get_slice(TypeSpace)); + + // Find the first input type that either references a type parameter OR + // some local type. + for input_ty in input_tys { + if ty_is_local(tcx, input_ty, infer_is_local) { + debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty); + + // First local input type. Check that there are no + // uncovered type parameters. + let uncovered_tys = uncovered_tys(tcx, input_ty, infer_is_local); + for uncovered_ty in uncovered_tys { + if let Some(param) = uncovered_ty.walk().find(|t| is_type_parameter(t)) { + debug!("orphan_check_trait_ref: uncovered type `{:?}`", param); + return Err(OrphanCheckErr::UncoveredTy(param)); + } + } + + // OK, found local type, all prior types upheld invariant. + return Ok(()); + } + + // Otherwise, enforce invariant that there are no type + // parameters reachable. + if !infer_is_local.0 { + if let Some(param) = input_ty.walk().find(|t| is_type_parameter(t)) { + debug!("orphan_check_trait_ref: uncovered type `{:?}`", param); + return Err(OrphanCheckErr::UncoveredTy(param)); + } + } + } + + // If we exit above loop, never found a local type. + debug!("orphan_check_trait_ref: no local type"); + return Err(OrphanCheckErr::NoLocalInputType); +} + +fn uncovered_tys<'tcx>(tcx: &TyCtxt<'tcx>, + ty: Ty<'tcx>, + infer_is_local: InferIsLocal) + -> Vec> +{ + if ty_is_local_constructor(tcx, ty, infer_is_local) { + vec![] + } else if fundamental_ty(tcx, ty) { + ty.walk_shallow() + .flat_map(|t| uncovered_tys(tcx, t, infer_is_local)) + .collect() + } else { + vec![ty] + } +} + +fn is_type_parameter<'tcx>(ty: Ty<'tcx>) -> bool { + match ty.sty { + // FIXME(#20590) straighten story about projection types + ty::TyProjection(..) | ty::TyParam(..) => true, + _ => false, + } +} + +fn ty_is_local<'tcx>(tcx: &TyCtxt<'tcx>, ty: Ty<'tcx>, infer_is_local: InferIsLocal) -> bool +{ + ty_is_local_constructor(tcx, ty, infer_is_local) || + fundamental_ty(tcx, ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, infer_is_local)) +} + +fn fundamental_ty<'tcx>(tcx: &TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool +{ + match ty.sty { + ty::TyBox(..) | ty::TyRef(..) => + true, + ty::TyEnum(def, _) | ty::TyStruct(def, _) => + def.is_fundamental(), + ty::TyTrait(ref data) => + tcx.has_attr(data.principal_def_id(), "fundamental"), + _ => + false + } +} + +fn ty_is_local_constructor<'tcx>(tcx: &TyCtxt<'tcx>, + ty: Ty<'tcx>, + infer_is_local: InferIsLocal) + -> bool +{ + debug!("ty_is_local_constructor({:?})", ty); + + match ty.sty { + ty::TyBool | + ty::TyChar | + ty::TyInt(..) | + ty::TyUint(..) | + ty::TyFloat(..) | + ty::TyStr | + ty::TyFnDef(..) | + ty::TyFnPtr(_) | + ty::TyArray(..) | + ty::TySlice(..) | + ty::TyRawPtr(..) | + ty::TyRef(..) | + ty::TyTuple(..) | + ty::TyParam(..) | + ty::TyProjection(..) => { + false + } + + ty::TyInfer(..) => { + infer_is_local.0 + } + + ty::TyEnum(def, _) | + ty::TyStruct(def, _) => { + def.did.is_local() + } + + ty::TyBox(_) => { // Box + let krate = tcx.lang_items.owned_box().map(|d| d.krate); + krate == Some(LOCAL_CRATE) + } + + ty::TyTrait(ref tt) => { + tt.principal_def_id().is_local() + } + + ty::TyError => { + true + } + + ty::TyClosure(..) => { + tcx.sess.bug( + &format!("ty_is_local invoked on unexpected type: {:?}", + ty)) + } + } +} diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs new file mode 100644 index 00000000000..c26aaeaf143 --- /dev/null +++ b/src/librustc/traits/error_reporting.rs @@ -0,0 +1,807 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::{ + FulfillmentError, + FulfillmentErrorCode, + MismatchedProjectionTypes, + Obligation, + ObligationCauseCode, + OutputTypeParameterMismatch, + TraitNotObjectSafe, + PredicateObligation, + SelectionError, + ObjectSafetyViolation, + MethodViolationCode, + object_safety_violations, +}; + +use fmt_macros::{Parser, Piece, Position}; +use middle::def_id::DefId; +use infer::InferCtxt; +use ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable}; +use ty::fast_reject; +use util::nodemap::{FnvHashMap, FnvHashSet}; + +use std::cmp; +use std::fmt; +use syntax::attr::{AttributeMethods, AttrMetaMethods}; +use syntax::codemap::Span; +use syntax::errors::DiagnosticBuilder; + +#[derive(Debug, PartialEq, Eq, Hash)] +pub struct TraitErrorKey<'tcx> { + span: Span, + predicate: ty::Predicate<'tcx> +} + +impl<'tcx> TraitErrorKey<'tcx> { + fn from_error<'a>(infcx: &InferCtxt<'a, 'tcx>, + e: &FulfillmentError<'tcx>) -> Self { + let predicate = + infcx.resolve_type_vars_if_possible(&e.obligation.predicate); + TraitErrorKey { + span: e.obligation.cause.span, + predicate: infcx.tcx.erase_regions(&predicate) + } + } +} + +pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + errors: &Vec>) { + for error in errors { + report_fulfillment_error(infcx, error); + } +} + +fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + error: &FulfillmentError<'tcx>) { + let error_key = TraitErrorKey::from_error(infcx, error); + debug!("report_fulfillment_errors({:?}) - key={:?}", + error, error_key); + if !infcx.reported_trait_errors.borrow_mut().insert(error_key) { + debug!("report_fulfillment_errors: skipping duplicate"); + return; + } + match error.code { + FulfillmentErrorCode::CodeSelectionError(ref e) => { + report_selection_error(infcx, &error.obligation, e); + } + FulfillmentErrorCode::CodeProjectionError(ref e) => { + report_projection_error(infcx, &error.obligation, e); + } + FulfillmentErrorCode::CodeAmbiguity => { + maybe_report_ambiguity(infcx, &error.obligation); + } + } +} + +pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + obligation: &PredicateObligation<'tcx>, + error: &MismatchedProjectionTypes<'tcx>) +{ + let predicate = + infcx.resolve_type_vars_if_possible(&obligation.predicate); + + // The TyError created by normalize_to_error can end up being unified + // into all obligations: for example, if our obligation is something + // like `$X = <() as Foo<$X>>::Out` and () does not implement Foo<_>, + // then $X will be unified with TyError, but the error still needs to be + // reported. + if !infcx.tcx.sess.has_errors() || !predicate.references_error() { + let mut err = struct_span_err!(infcx.tcx.sess, obligation.cause.span, E0271, + "type mismatch resolving `{}`: {}", + predicate, + error.err); + note_obligation_cause(infcx, &mut err, obligation); + err.emit(); + } +} + +fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + trait_ref: &TraitRef<'tcx>, + span: Span) -> Option { + let def_id = trait_ref.def_id; + let mut report = None; + for item in infcx.tcx.get_attrs(def_id).iter() { + if item.check_name("rustc_on_unimplemented") { + let err_sp = item.meta().span.substitute_dummy(span); + let def = infcx.tcx.lookup_trait_def(def_id); + let trait_str = def.trait_ref.to_string(); + if let Some(ref istring) = item.value_str() { + let mut generic_map = def.generics.types.iter_enumerated() + .map(|(param, i, gen)| { + (gen.name.as_str().to_string(), + trait_ref.substs.types.get(param, i) + .to_string()) + }).collect::>(); + generic_map.insert("Self".to_string(), + trait_ref.self_ty().to_string()); + let parser = Parser::new(&istring); + let mut errored = false; + let err: String = parser.filter_map(|p| { + match p { + Piece::String(s) => Some(s), + Piece::NextArgument(a) => match a.position { + Position::ArgumentNamed(s) => match generic_map.get(s) { + Some(val) => Some(val), + None => { + span_err!(infcx.tcx.sess, err_sp, E0272, + "the #[rustc_on_unimplemented] \ + attribute on \ + trait definition for {} refers to \ + non-existent type parameter {}", + trait_str, s); + errored = true; + None + } + }, + _ => { + span_err!(infcx.tcx.sess, err_sp, E0273, + "the #[rustc_on_unimplemented] \ + attribute on \ + trait definition for {} must have named \ + format arguments, \ + eg `#[rustc_on_unimplemented = \ + \"foo {{T}}\"]`", + trait_str); + errored = true; + None + } + } + } + }).collect(); + // Report only if the format string checks out + if !errored { + report = Some(err); + } + } else { + span_err!(infcx.tcx.sess, err_sp, E0274, + "the #[rustc_on_unimplemented] attribute on \ + trait definition for {} must have a value, \ + eg `#[rustc_on_unimplemented = \"foo\"]`", + trait_str); + } + break; + } + } + report +} + +/// Reports that an overflow has occurred and halts compilation. We +/// halt compilation unconditionally because it is important that +/// overflows never be masked -- they basically represent computations +/// whose result could not be truly determined and thus we can't say +/// if the program type checks or not -- and they are unusual +/// occurrences in any case. +pub fn report_overflow_error<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, + obligation: &Obligation<'tcx, T>, + suggest_increasing_limit: bool) + -> ! + where T: fmt::Display + TypeFoldable<'tcx> +{ + let predicate = + infcx.resolve_type_vars_if_possible(&obligation.predicate); + let mut err = struct_span_err!(infcx.tcx.sess, obligation.cause.span, E0275, + "overflow evaluating the requirement `{}`", + predicate); + + if suggest_increasing_limit { + suggest_new_overflow_limit(infcx.tcx, &mut err, obligation.cause.span); + } + + note_obligation_cause(infcx, &mut err, obligation); + + err.emit(); + infcx.tcx.sess.abort_if_errors(); + unreachable!(); +} + +/// Reports that a cycle was detected which led to overflow and halts +/// compilation. This is equivalent to `report_overflow_error` except +/// that we can give a more helpful error message (and, in particular, +/// we do not suggest increasing the overflow limit, which is not +/// going to help). +pub fn report_overflow_error_cycle<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + cycle: &Vec>) + -> ! +{ + assert!(cycle.len() > 1); + + debug!("report_overflow_error_cycle(cycle length = {})", cycle.len()); + + let cycle = infcx.resolve_type_vars_if_possible(cycle); + + debug!("report_overflow_error_cycle: cycle={:?}", cycle); + + assert_eq!(&cycle[0].predicate, &cycle.last().unwrap().predicate); + + try_report_overflow_error_type_of_infinite_size(infcx, &cycle); + report_overflow_error(infcx, &cycle[0], false); +} + +/// If a cycle results from evaluated whether something is Sized, that +/// is a particular special case that always results from a struct or +/// enum definition that lacks indirection (e.g., `struct Foo { x: Foo +/// }`). We wish to report a targeted error for this case. +pub fn try_report_overflow_error_type_of_infinite_size<'a, 'tcx>( + infcx: &InferCtxt<'a, 'tcx>, + cycle: &[PredicateObligation<'tcx>]) +{ + let sized_trait = match infcx.tcx.lang_items.sized_trait() { + Some(v) => v, + None => return, + }; + let top_is_sized = { + match cycle[0].predicate { + ty::Predicate::Trait(ref data) => data.def_id() == sized_trait, + _ => false, + } + }; + if !top_is_sized { + return; + } + + // The only way to have a type of infinite size is to have, + // somewhere, a struct/enum type involved. Identify all such types + // and report the cycle to the user. + + let struct_enum_tys: Vec<_> = + cycle.iter() + .flat_map(|obligation| match obligation.predicate { + ty::Predicate::Trait(ref data) => { + assert_eq!(data.def_id(), sized_trait); + let self_ty = data.skip_binder().trait_ref.self_ty(); // (*) + // (*) ok to skip binder because this is just + // error reporting and regions don't really + // matter + match self_ty.sty { + ty::TyEnum(..) | ty::TyStruct(..) => Some(self_ty), + _ => None, + } + } + _ => { + infcx.tcx.sess.span_bug(obligation.cause.span, + &format!("Sized cycle involving non-trait-ref: {:?}", + obligation.predicate)); + } + }) + .collect(); + + assert!(!struct_enum_tys.is_empty()); + + // This is a bit tricky. We want to pick a "main type" in the + // listing that is local to the current crate, so we can give a + // good span to the user. But it might not be the first one in our + // cycle list. So find the first one that is local and then + // rotate. + let (main_index, main_def_id) = + struct_enum_tys.iter() + .enumerate() + .filter_map(|(index, ty)| match ty.sty { + ty::TyEnum(adt_def, _) | ty::TyStruct(adt_def, _) + if adt_def.did.is_local() => + Some((index, adt_def.did)), + _ => + None, + }) + .next() + .unwrap(); // should always be SOME local type involved! + + // Rotate so that the "main" type is at index 0. + let struct_enum_tys: Vec<_> = + struct_enum_tys.iter() + .cloned() + .skip(main_index) + .chain(struct_enum_tys.iter().cloned().take(main_index)) + .collect(); + + let tcx = infcx.tcx; + let mut err = recursive_type_with_infinite_size_error(tcx, main_def_id); + let len = struct_enum_tys.len(); + if len > 2 { + let span = tcx.map.span_if_local(main_def_id).unwrap(); + err.fileline_note(span, + &format!("type `{}` is embedded within `{}`...", + struct_enum_tys[0], + struct_enum_tys[1])); + for &next_ty in &struct_enum_tys[1..len-1] { + err.fileline_note(span, + &format!("...which in turn is embedded within `{}`...", next_ty)); + } + err.fileline_note(span, + &format!("...which in turn is embedded within `{}`, \ + completing the cycle.", + struct_enum_tys[len-1])); + } + err.emit(); + infcx.tcx.sess.abort_if_errors(); + unreachable!(); +} + +pub fn recursive_type_with_infinite_size_error<'tcx>(tcx: &TyCtxt<'tcx>, + type_def_id: DefId) + -> DiagnosticBuilder<'tcx> +{ + assert!(type_def_id.is_local()); + let span = tcx.map.span_if_local(type_def_id).unwrap(); + let mut err = struct_span_err!(tcx.sess, span, E0072, "recursive type `{}` has infinite size", + tcx.item_path_str(type_def_id)); + err.fileline_help(span, &format!("insert indirection (e.g., a `Box`, `Rc`, or `&`) \ + at some point to make `{}` representable", + tcx.item_path_str(type_def_id))); + err +} + +pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + obligation: &PredicateObligation<'tcx>, + error: &SelectionError<'tcx>) +{ + match *error { + SelectionError::Unimplemented => { + if let ObligationCauseCode::CompareImplMethodObligation = obligation.cause.code { + span_err!( + infcx.tcx.sess, obligation.cause.span, E0276, + "the requirement `{}` appears on the impl \ + method but not on the corresponding trait method", + obligation.predicate); + } else { + match obligation.predicate { + ty::Predicate::Trait(ref trait_predicate) => { + let trait_predicate = + infcx.resolve_type_vars_if_possible(trait_predicate); + + if !infcx.tcx.sess.has_errors() || !trait_predicate.references_error() { + let trait_ref = trait_predicate.to_poly_trait_ref(); + let mut err = struct_span_err!( + infcx.tcx.sess, obligation.cause.span, E0277, + "the trait `{}` is not implemented for the type `{}`", + trait_ref, trait_ref.self_ty()); + + // Check if it has a custom "#[rustc_on_unimplemented]" + // error message, report with that message if it does + let custom_note = report_on_unimplemented(infcx, &trait_ref.0, + obligation.cause.span); + if let Some(s) = custom_note { + err.fileline_note(obligation.cause.span, &s); + } else { + let simp = fast_reject::simplify_type(infcx.tcx, + trait_ref.self_ty(), + true); + let mut impl_candidates = Vec::new(); + let trait_def = infcx.tcx.lookup_trait_def(trait_ref.def_id()); + + match simp { + Some(simp) => trait_def.for_each_impl(infcx.tcx, |def_id| { + let imp = infcx.tcx.impl_trait_ref(def_id).unwrap(); + let imp_simp = fast_reject::simplify_type(infcx.tcx, + imp.self_ty(), + true); + if let Some(imp_simp) = imp_simp { + if simp != imp_simp { + return; + } + } + impl_candidates.push(imp); + }), + None => trait_def.for_each_impl(infcx.tcx, |def_id| { + impl_candidates.push( + infcx.tcx.impl_trait_ref(def_id).unwrap()); + }) + }; + + if impl_candidates.len() > 0 { + err.fileline_help( + obligation.cause.span, + &format!("the following implementations were found:")); + + let end = cmp::min(4, impl_candidates.len()); + for candidate in &impl_candidates[0..end] { + err.fileline_help(obligation.cause.span, + &format!(" {:?}", candidate)); + } + if impl_candidates.len() > 4 { + err.fileline_help(obligation.cause.span, + &format!("and {} others", + impl_candidates.len()-4)); + } + } + } + note_obligation_cause(infcx, &mut err, obligation); + err.emit(); + } + }, + ty::Predicate::Equate(ref predicate) => { + let predicate = infcx.resolve_type_vars_if_possible(predicate); + let err = infcx.equality_predicate(obligation.cause.span, + &predicate).err().unwrap(); + let mut err = struct_span_err!( + infcx.tcx.sess, obligation.cause.span, E0278, + "the requirement `{}` is not satisfied (`{}`)", + predicate, + err); + note_obligation_cause(infcx, &mut err, obligation); + err.emit(); + } + + ty::Predicate::RegionOutlives(ref predicate) => { + let predicate = infcx.resolve_type_vars_if_possible(predicate); + let err = infcx.region_outlives_predicate(obligation.cause.span, + &predicate).err().unwrap(); + let mut err = struct_span_err!( + infcx.tcx.sess, obligation.cause.span, E0279, + "the requirement `{}` is not satisfied (`{}`)", + predicate, + err); + note_obligation_cause(infcx, &mut err, obligation); + err.emit(); + } + + ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => { + let predicate = + infcx.resolve_type_vars_if_possible(&obligation.predicate); + let mut err = struct_span_err!( + infcx.tcx.sess, obligation.cause.span, E0280, + "the requirement `{}` is not satisfied", + predicate); + note_obligation_cause(infcx, &mut err, obligation); + err.emit(); + } + + ty::Predicate::ObjectSafe(trait_def_id) => { + let violations = object_safety_violations( + infcx.tcx, trait_def_id); + let mut err = report_object_safety_error(infcx.tcx, + obligation.cause.span, + trait_def_id, + violations); + note_obligation_cause(infcx, &mut err, obligation); + err.emit(); + } + + ty::Predicate::WellFormed(ty) => { + // WF predicates cannot themselves make + // errors. They can only block due to + // ambiguity; otherwise, they always + // degenerate into other obligations + // (which may fail). + infcx.tcx.sess.span_bug( + obligation.cause.span, + &format!("WF predicate not satisfied for {:?}", ty)); + } + } + } + } + + OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => { + let expected_trait_ref = infcx.resolve_type_vars_if_possible(&*expected_trait_ref); + let actual_trait_ref = infcx.resolve_type_vars_if_possible(&*actual_trait_ref); + if !actual_trait_ref.self_ty().references_error() { + let mut err = struct_span_err!( + infcx.tcx.sess, obligation.cause.span, E0281, + "type mismatch: the type `{}` implements the trait `{}`, \ + but the trait `{}` is required ({})", + expected_trait_ref.self_ty(), + expected_trait_ref, + actual_trait_ref, + e); + note_obligation_cause(infcx, &mut err, obligation); + err.emit(); + } + } + + TraitNotObjectSafe(did) => { + let violations = object_safety_violations(infcx.tcx, did); + let mut err = report_object_safety_error(infcx.tcx, obligation.cause.span, did, + violations); + note_obligation_cause(infcx, &mut err, obligation); + err.emit(); + } + } +} + +pub fn report_object_safety_error<'tcx>(tcx: &TyCtxt<'tcx>, + span: Span, + trait_def_id: DefId, + violations: Vec) + -> DiagnosticBuilder<'tcx> +{ + let mut err = struct_span_err!( + tcx.sess, span, E0038, + "the trait `{}` cannot be made into an object", + tcx.item_path_str(trait_def_id)); + + let mut reported_violations = FnvHashSet(); + for violation in violations { + if !reported_violations.insert(violation.clone()) { + continue; + } + match violation { + ObjectSafetyViolation::SizedSelf => { + err.fileline_note( + span, + "the trait cannot require that `Self : Sized`"); + } + + ObjectSafetyViolation::SupertraitSelf => { + err.fileline_note( + span, + "the trait cannot use `Self` as a type parameter \ + in the supertrait listing"); + } + + ObjectSafetyViolation::Method(method, + MethodViolationCode::StaticMethod) => { + err.fileline_note( + span, + &format!("method `{}` has no receiver", + method.name)); + } + + ObjectSafetyViolation::Method(method, + MethodViolationCode::ReferencesSelf) => { + err.fileline_note( + span, + &format!("method `{}` references the `Self` type \ + in its arguments or return type", + method.name)); + } + + ObjectSafetyViolation::Method(method, + MethodViolationCode::Generic) => { + err.fileline_note( + span, + &format!("method `{}` has generic type parameters", + method.name)); + } + } + } + err +} + +pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + obligation: &PredicateObligation<'tcx>) { + // Unable to successfully determine, probably means + // insufficient type information, but could mean + // ambiguous impls. The latter *ought* to be a + // coherence violation, so we don't report it here. + + let predicate = infcx.resolve_type_vars_if_possible(&obligation.predicate); + + debug!("maybe_report_ambiguity(predicate={:?}, obligation={:?})", + predicate, + obligation); + + match predicate { + ty::Predicate::Trait(ref data) => { + let trait_ref = data.to_poly_trait_ref(); + let self_ty = trait_ref.self_ty(); + let all_types = &trait_ref.substs().types; + if all_types.references_error() { + } else { + // Typically, this ambiguity should only happen if + // there are unresolved type inference variables + // (otherwise it would suggest a coherence + // failure). But given #21974 that is not necessarily + // the case -- we can have multiple where clauses that + // are only distinguished by a region, which results + // in an ambiguity even when all types are fully + // known, since we don't dispatch based on region + // relationships. + + // This is kind of a hack: it frequently happens that some earlier + // error prevents types from being fully inferred, and then we get + // a bunch of uninteresting errors saying something like " doesn't implement Sized". It may even be true that we + // could just skip over all checks where the self-ty is an + // inference variable, but I was afraid that there might be an + // inference variable created, registered as an obligation, and + // then never forced by writeback, and hence by skipping here we'd + // be ignoring the fact that we don't KNOW the type works + // out. Though even that would probably be harmless, given that + // we're only talking about builtin traits, which are known to be + // inhabited. But in any case I just threw in this check for + // has_errors() to be sure that compilation isn't happening + // anyway. In that case, why inundate the user. + if !infcx.tcx.sess.has_errors() { + if + infcx.tcx.lang_items.sized_trait() + .map_or(false, |sized_id| sized_id == trait_ref.def_id()) + { + need_type_info(infcx, obligation.cause.span, self_ty); + } else { + let mut err = struct_span_err!(infcx.tcx.sess, obligation.cause.span, E0283, + "type annotations required: \ + cannot resolve `{}`", + predicate); + note_obligation_cause(infcx, &mut err, obligation); + err.emit(); + } + } + } + } + + ty::Predicate::WellFormed(ty) => { + // Same hacky approach as above to avoid deluging user + // with error messages. + if !ty.references_error() && !infcx.tcx.sess.has_errors() { + need_type_info(infcx, obligation.cause.span, ty); + } + } + + _ => { + if !infcx.tcx.sess.has_errors() { + let mut err = struct_span_err!(infcx.tcx.sess, obligation.cause.span, E0284, + "type annotations required: cannot resolve `{}`", + predicate); + note_obligation_cause(infcx, &mut err, obligation); + err.emit(); + } + } + } +} + +fn need_type_info<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + span: Span, + ty: Ty<'tcx>) +{ + span_err!(infcx.tcx.sess, span, E0282, + "unable to infer enough type information about `{}`; \ + type annotations or generic parameter binding required", + ty); +} + +fn note_obligation_cause<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, + err: &mut DiagnosticBuilder, + obligation: &Obligation<'tcx, T>) + where T: fmt::Display +{ + note_obligation_cause_code(infcx, + err, + &obligation.predicate, + obligation.cause.span, + &obligation.cause.code); +} + +fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, + err: &mut DiagnosticBuilder, + predicate: &T, + cause_span: Span, + cause_code: &ObligationCauseCode<'tcx>) + where T: fmt::Display +{ + let tcx = infcx.tcx; + match *cause_code { + ObligationCauseCode::MiscObligation => { } + ObligationCauseCode::SliceOrArrayElem => { + err.fileline_note( + cause_span, + "slice and array elements must have `Sized` type"); + } + ObligationCauseCode::ProjectionWf(data) => { + err.fileline_note( + cause_span, + &format!("required so that the projection `{}` is well-formed", + data)); + } + ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => { + err.fileline_note( + cause_span, + &format!("required so that reference `{}` does not outlive its referent", + ref_ty)); + } + ObligationCauseCode::ItemObligation(item_def_id) => { + let item_name = tcx.item_path_str(item_def_id); + err.fileline_note( + cause_span, + &format!("required by `{}`", item_name)); + } + ObligationCauseCode::ObjectCastObligation(object_ty) => { + err.fileline_note( + cause_span, + &format!( + "required for the cast to the object type `{}`", + infcx.ty_to_string(object_ty))); + } + ObligationCauseCode::RepeatVec => { + err.fileline_note( + cause_span, + "the `Copy` trait is required because the \ + repeated element will be copied"); + } + ObligationCauseCode::VariableType(_) => { + err.fileline_note( + cause_span, + "all local variables must have a statically known size"); + } + ObligationCauseCode::ReturnType => { + err.fileline_note( + cause_span, + "the return type of a function must have a \ + statically known size"); + } + ObligationCauseCode::AssignmentLhsSized => { + err.fileline_note( + cause_span, + "the left-hand-side of an assignment must have a statically known size"); + } + ObligationCauseCode::StructInitializerSized => { + err.fileline_note( + cause_span, + "structs must have a statically known size to be initialized"); + } + ObligationCauseCode::ClosureCapture(var_id, _, builtin_bound) => { + let def_id = tcx.lang_items.from_builtin_kind(builtin_bound).unwrap(); + let trait_name = tcx.item_path_str(def_id); + let name = tcx.local_var_name_str(var_id); + err.fileline_note( + cause_span, + &format!("the closure that captures `{}` requires that all captured variables \ + implement the trait `{}`", + name, + trait_name)); + } + ObligationCauseCode::FieldSized => { + err.fileline_note( + cause_span, + "only the last field of a struct or enum variant \ + may have a dynamically sized type"); + } + ObligationCauseCode::SharedStatic => { + err.fileline_note( + cause_span, + "shared static variables must have a type that implements `Sync`"); + } + ObligationCauseCode::BuiltinDerivedObligation(ref data) => { + let parent_trait_ref = infcx.resolve_type_vars_if_possible(&data.parent_trait_ref); + err.fileline_note( + cause_span, + &format!("required because it appears within the type `{}`", + parent_trait_ref.0.self_ty())); + let parent_predicate = parent_trait_ref.to_predicate(); + note_obligation_cause_code(infcx, + err, + &parent_predicate, + cause_span, + &data.parent_code); + } + ObligationCauseCode::ImplDerivedObligation(ref data) => { + let parent_trait_ref = infcx.resolve_type_vars_if_possible(&data.parent_trait_ref); + err.fileline_note( + cause_span, + &format!("required because of the requirements on the impl of `{}` for `{}`", + parent_trait_ref, + parent_trait_ref.0.self_ty())); + let parent_predicate = parent_trait_ref.to_predicate(); + note_obligation_cause_code(infcx, + err, + &parent_predicate, + cause_span, + &data.parent_code); + } + ObligationCauseCode::CompareImplMethodObligation => { + err.fileline_note( + cause_span, + &format!("the requirement `{}` appears on the impl method \ + but not on the corresponding trait method", + predicate)); + } + } +} + +fn suggest_new_overflow_limit(tcx: &TyCtxt, err:&mut DiagnosticBuilder, span: Span) { + let current_limit = tcx.sess.recursion_limit.get(); + let suggested_limit = current_limit * 2; + err.fileline_note( + span, + &format!( + "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", + suggested_limit)); +} diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs new file mode 100644 index 00000000000..321144126c9 --- /dev/null +++ b/src/librustc/traits/fulfill.rs @@ -0,0 +1,764 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use dep_graph::DepGraph; +use infer::InferCtxt; +use ty::{self, Ty, TyCtxt, TypeFoldable, ToPolyTraitRef}; +use rustc_data_structures::obligation_forest::{Backtrace, ObligationForest, Error}; +use std::iter; +use syntax::ast; +use util::common::ErrorReported; +use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap}; + +use super::CodeAmbiguity; +use super::CodeProjectionError; +use super::CodeSelectionError; +use super::is_object_safe; +use super::FulfillmentError; +use super::FulfillmentErrorCode; +use super::ObligationCause; +use super::PredicateObligation; +use super::project; +use super::report_overflow_error_cycle; +use super::select::SelectionContext; +use super::Unimplemented; +use super::util::predicate_for_builtin_bound; + +pub struct GlobalFulfilledPredicates<'tcx> { + set: FnvHashSet>, + dep_graph: DepGraph, +} + +#[derive(Debug)] +pub struct LocalFulfilledPredicates<'tcx> { + set: FnvHashSet> +} + +/// The fulfillment context is used to drive trait resolution. It +/// consists of a list of obligations that must be (eventually) +/// satisfied. The job is to track which are satisfied, which yielded +/// errors, and which are still pending. At any point, users can call +/// `select_where_possible`, and the fulfilment context will try to do +/// selection, retaining only those obligations that remain +/// ambiguous. This may be helpful in pushing type inference +/// along. Once all type inference constraints have been generated, the +/// method `select_all_or_error` can be used to report any remaining +/// ambiguous cases as errors. +pub struct FulfillmentContext<'tcx> { + // a simple cache that aims to cache *exact duplicate obligations* + // and avoid adding them twice. This serves a different purpose + // than the `SelectionCache`: it avoids duplicate errors and + // permits recursive obligations, which are often generated from + // traits like `Send` et al. + // + // Note that because of type inference, a predicate can still + // occur twice in the predicates list, for example when 2 + // initially-distinct type variables are unified after being + // inserted. Deduplicating the predicate set on selection had a + // significant performance cost the last time I checked. + duplicate_set: LocalFulfilledPredicates<'tcx>, + + // A list of all obligations that have been registered with this + // fulfillment context. + predicates: ObligationForest, + LocalFulfilledPredicates<'tcx>>, + + // A set of constraints that regionck must validate. Each + // constraint has the form `T:'a`, meaning "some type `T` must + // outlive the lifetime 'a". These constraints derive from + // instantiated type parameters. So if you had a struct defined + // like + // + // struct Foo { ... } + // + // then in some expression `let x = Foo { ... }` it will + // instantiate the type parameter `T` with a fresh type `$0`. At + // the same time, it will record a region obligation of + // `$0:'static`. This will get checked later by regionck. (We + // can't generally check these things right away because we have + // to wait until types are resolved.) + // + // These are stored in a map keyed to the id of the innermost + // enclosing fn body / static initializer expression. This is + // because the location where the obligation was incurred can be + // relevant with respect to which sublifetime assumptions are in + // place. The reason that we store under the fn-id, and not + // something more fine-grained, is so that it is easier for + // regionck to be sure that it has found *all* the region + // obligations (otherwise, it's easy to fail to walk to a + // particular node-id). + region_obligations: NodeMap>>, +} + +#[derive(Clone)] +pub struct RegionObligation<'tcx> { + pub sub_region: ty::Region, + pub sup_type: Ty<'tcx>, + pub cause: ObligationCause<'tcx>, +} + +#[derive(Clone, Debug)] +pub struct PendingPredicateObligation<'tcx> { + pub obligation: PredicateObligation<'tcx>, + pub stalled_on: Vec>, +} + +impl<'tcx> FulfillmentContext<'tcx> { + /// Creates a new fulfillment context. + pub fn new() -> FulfillmentContext<'tcx> { + FulfillmentContext { + duplicate_set: LocalFulfilledPredicates::new(), + predicates: ObligationForest::new(), + region_obligations: NodeMap(), + } + } + + /// "Normalize" a projection type `::X` by + /// creating a fresh type variable `$0` as well as a projection + /// predicate `::X == $0`. When the + /// inference engine runs, it will attempt to find an impl of + /// `SomeTrait` or a where clause that lets us unify `$0` with + /// something concrete. If this fails, we'll unify `$0` with + /// `projection_ty` again. + pub fn normalize_projection_type<'a>(&mut self, + infcx: &InferCtxt<'a,'tcx>, + projection_ty: ty::ProjectionTy<'tcx>, + cause: ObligationCause<'tcx>) + -> Ty<'tcx> + { + debug!("normalize_projection_type(projection_ty={:?})", + projection_ty); + + assert!(!projection_ty.has_escaping_regions()); + + // FIXME(#20304) -- cache + + let mut selcx = SelectionContext::new(infcx); + let normalized = project::normalize_projection_type(&mut selcx, projection_ty, cause, 0); + + for obligation in normalized.obligations { + self.register_predicate_obligation(infcx, obligation); + } + + debug!("normalize_projection_type: result={:?}", normalized.value); + + normalized.value + } + + pub fn register_builtin_bound<'a>(&mut self, + infcx: &InferCtxt<'a,'tcx>, + ty: Ty<'tcx>, + builtin_bound: ty::BuiltinBound, + cause: ObligationCause<'tcx>) + { + match predicate_for_builtin_bound(infcx.tcx, cause, builtin_bound, 0, ty) { + Ok(predicate) => { + self.register_predicate_obligation(infcx, predicate); + } + Err(ErrorReported) => { } + } + } + + pub fn register_region_obligation<'a>(&mut self, + t_a: Ty<'tcx>, + r_b: ty::Region, + cause: ObligationCause<'tcx>) + { + register_region_obligation(t_a, r_b, cause, &mut self.region_obligations); + } + + pub fn register_predicate_obligation<'a>(&mut self, + infcx: &InferCtxt<'a,'tcx>, + obligation: PredicateObligation<'tcx>) + { + // this helps to reduce duplicate errors, as well as making + // debug output much nicer to read and so on. + let obligation = infcx.resolve_type_vars_if_possible(&obligation); + + assert!(!obligation.has_escaping_regions()); + + if self.is_duplicate_or_add(infcx.tcx, &obligation.predicate) { + debug!("register_predicate_obligation({:?}) -- already seen, skip", obligation); + return; + } + + debug!("register_predicate_obligation({:?})", obligation); + let obligation = PendingPredicateObligation { + obligation: obligation, + stalled_on: vec![] + }; + self.predicates.push_tree(obligation, LocalFulfilledPredicates::new()); + } + + pub fn region_obligations(&self, + body_id: ast::NodeId) + -> &[RegionObligation<'tcx>] + { + match self.region_obligations.get(&body_id) { + None => Default::default(), + Some(vec) => vec, + } + } + + pub fn select_all_or_error<'a>(&mut self, + infcx: &InferCtxt<'a,'tcx>) + -> Result<(),Vec>> + { + self.select_where_possible(infcx)?; + let errors: Vec<_> = + self.predicates.to_errors(CodeAmbiguity) + .into_iter() + .map(|e| to_fulfillment_error(e)) + .collect(); + if errors.is_empty() { + Ok(()) + } else { + Err(errors) + } + } + + pub fn select_where_possible<'a>(&mut self, + infcx: &InferCtxt<'a,'tcx>) + -> Result<(),Vec>> + { + let mut selcx = SelectionContext::new(infcx); + self.select(&mut selcx) + } + + pub fn pending_obligations(&self) -> Vec> { + self.predicates.pending_obligations() + } + + fn is_duplicate_or_add(&mut self, + tcx: &TyCtxt<'tcx>, + predicate: &ty::Predicate<'tcx>) + -> bool { + // For "global" predicates -- that is, predicates that don't + // involve type parameters, inference variables, or regions + // other than 'static -- we can check the cache in the tcx, + // which allows us to leverage work from other threads. Note + // that we don't add anything to this cache yet (unlike the + // local cache). This is because the tcx cache maintains the + // invariant that it only contains things that have been + // proven, and we have not yet proven that `predicate` holds. + if tcx.fulfilled_predicates.borrow().check_duplicate(predicate) { + return true; + } + + // If `predicate` is not global, or not present in the tcx + // cache, we can still check for it in our local cache and add + // it if not present. Note that if we find this predicate in + // the local cache we can stop immediately, without reporting + // any errors, even though we don't know yet if it is + // true. This is because, while we don't yet know if the + // predicate holds, we know that this same fulfillment context + // already is in the process of finding out. + self.duplicate_set.is_duplicate_or_add(predicate) + } + + /// Attempts to select obligations using `selcx`. If `only_new_obligations` is true, then it + /// only attempts to select obligations that haven't been seen before. + fn select<'a>(&mut self, + selcx: &mut SelectionContext<'a, 'tcx>) + -> Result<(),Vec>> + { + debug!("select(obligation-forest-size={})", self.predicates.len()); + + let mut errors = Vec::new(); + + loop { + debug!("select: starting another iteration"); + + // Process pending obligations. + let outcome = { + let region_obligations = &mut self.region_obligations; + self.predicates.process_obligations( + |obligation, tree, backtrace| process_predicate(selcx, + tree, + obligation, + backtrace, + region_obligations)) + }; + + debug!("select: outcome={:?}", outcome); + + // these are obligations that were proven to be true. + for pending_obligation in outcome.completed { + let predicate = &pending_obligation.obligation.predicate; + selcx.tcx().fulfilled_predicates.borrow_mut().add_if_global(predicate); + } + + errors.extend( + outcome.errors.into_iter() + .map(|e| to_fulfillment_error(e))); + + // If nothing new was added, no need to keep looping. + if outcome.stalled { + break; + } + } + + debug!("select({} predicates remaining, {} errors) done", + self.predicates.len(), errors.len()); + + if errors.is_empty() { + Ok(()) + } else { + Err(errors) + } + } +} + +/// Like `process_predicate1`, but wrap result into a pending predicate. +fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, + tree_cache: &mut LocalFulfilledPredicates<'tcx>, + pending_obligation: &mut PendingPredicateObligation<'tcx>, + mut backtrace: Backtrace>, + region_obligations: &mut NodeMap>>) + -> Result>>, + FulfillmentErrorCode<'tcx>> +{ + match process_predicate1(selcx, pending_obligation, backtrace.clone(), region_obligations) { + Ok(Some(v)) => { + // FIXME(#30977) The code below is designed to detect (and + // permit) DAGs, while still ensuring that the reasoning + // is acyclic. However, it does a few things + // suboptimally. For example, it refreshes type variables + // a lot, probably more than needed, but also less than + // you might want. + // + // - more than needed: I want to be very sure we don't + // accidentally treat a cycle as a DAG, so I am + // refreshing type variables as we walk the ancestors; + // but we are going to repeat this a lot, which is + // sort of silly, and it would be nicer to refresh + // them *in place* so that later predicate processing + // can benefit from the same work; + // - less than you might want: we only add items in the cache here, + // but maybe we learn more about type variables and could add them into + // the cache later on. + + let tcx = selcx.tcx(); + + // Compute a little FnvHashSet for the ancestors. We only + // do this the first time that we care. + let mut cache = None; + let mut is_ancestor = |predicate: &ty::Predicate<'tcx>| { + if cache.is_none() { + let mut c = FnvHashSet(); + for ancestor in backtrace.by_ref() { + // Ugh. This just feels ridiculously + // inefficient. But we need to compare + // predicates without being concerned about + // the vagaries of type inference, so for now + // just ensure that they are always + // up-to-date. (I suppose we could just use a + // snapshot and check if they are unifiable?) + let resolved_predicate = + selcx.infcx().resolve_type_vars_if_possible( + &ancestor.obligation.predicate); + c.insert(resolved_predicate); + } + cache = Some(c); + } + + cache.as_ref().unwrap().contains(predicate) + }; + + let pending_predicate_obligations: Vec<_> = + v.into_iter() + .filter_map(|obligation| { + // Probably silly, but remove any inference + // variables. This is actually crucial to the + // ancestor check below, but it's not clear that + // it makes sense to ALWAYS do it. + let obligation = selcx.infcx().resolve_type_vars_if_possible(&obligation); + + // Screen out obligations that we know globally + // are true. This should really be the DAG check + // mentioned above. + if tcx.fulfilled_predicates.borrow().check_duplicate(&obligation.predicate) { + return None; + } + + // Check whether this obligation appears somewhere else in the tree. + if tree_cache.is_duplicate_or_add(&obligation.predicate) { + // If the obligation appears as a parent, + // allow it, because that is a cycle. + // Otherwise though we can just ignore + // it. Note that we have to be careful around + // inference variables here -- for the + // purposes of the ancestor check, we retain + // the invariant that all type variables are + // fully refreshed. + if !is_ancestor(&obligation.predicate) { + return None; + } + } + + Some(PendingPredicateObligation { + obligation: obligation, + stalled_on: vec![] + }) + }) + .collect(); + + Ok(Some(pending_predicate_obligations)) + } + Ok(None) => Ok(None), + Err(e) => Err(e) + } +} + + +/// Return the set of type variables contained in a trait ref +fn trait_ref_type_vars<'a, 'tcx>(selcx: &mut SelectionContext<'a, 'tcx>, + t: ty::PolyTraitRef<'tcx>) -> Vec> +{ + t.skip_binder() // ok b/c this check doesn't care about regions + .input_types() + .iter() + .map(|t| selcx.infcx().resolve_type_vars_if_possible(t)) + .filter(|t| t.has_infer_types()) + .flat_map(|t| t.walk()) + .filter(|t| match t.sty { ty::TyInfer(_) => true, _ => false }) + .collect() +} + +/// Processes a predicate obligation and returns either: +/// - `Ok(Some(v))` if the predicate is true, presuming that `v` are also true +/// - `Ok(None)` if we don't have enough info to be sure +/// - `Err` if the predicate does not hold +fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, + pending_obligation: &mut PendingPredicateObligation<'tcx>, + backtrace: Backtrace>, + region_obligations: &mut NodeMap>>) + -> Result>>, + FulfillmentErrorCode<'tcx>> +{ + // if we were stalled on some unresolved variables, first check + // whether any of them have been resolved; if not, don't bother + // doing more work yet + if !pending_obligation.stalled_on.is_empty() { + if pending_obligation.stalled_on.iter().all(|&ty| { + let resolved_ty = selcx.infcx().shallow_resolve(&ty); + resolved_ty == ty // nothing changed here + }) { + debug!("process_predicate: pending obligation {:?} still stalled on {:?}", + selcx.infcx().resolve_type_vars_if_possible(&pending_obligation.obligation), + pending_obligation.stalled_on); + return Ok(None); + } + pending_obligation.stalled_on = vec![]; + } + + let obligation = &mut pending_obligation.obligation; + + // If we exceed the recursion limit, take a moment to look for a + // cycle so we can give a better error report from here, where we + // have more context. + let recursion_limit = selcx.tcx().sess.recursion_limit.get(); + if obligation.recursion_depth >= recursion_limit { + if let Some(cycle) = scan_for_cycle(obligation, &backtrace) { + report_overflow_error_cycle(selcx.infcx(), &cycle); + } + } + + if obligation.predicate.has_infer_types() { + obligation.predicate = selcx.infcx().resolve_type_vars_if_possible(&obligation.predicate); + } + + match obligation.predicate { + ty::Predicate::Trait(ref data) => { + if selcx.tcx().fulfilled_predicates.borrow().check_duplicate_trait(data) { + return Ok(Some(vec![])); + } + + if coinductive_match(selcx, obligation, data, &backtrace) { + return Ok(Some(vec![])); + } + + let trait_obligation = obligation.with(data.clone()); + match selcx.select(&trait_obligation) { + Ok(Some(vtable)) => { + info!("selecting trait `{:?}` at depth {} yielded Ok(Some)", + data, obligation.recursion_depth); + Ok(Some(vtable.nested_obligations())) + } + Ok(None) => { + info!("selecting trait `{:?}` at depth {} yielded Ok(None)", + data, obligation.recursion_depth); + + // This is a bit subtle: for the most part, the + // only reason we can fail to make progress on + // trait selection is because we don't have enough + // information about the types in the trait. One + // exception is that we sometimes haven't decided + // what kind of closure a closure is. *But*, in + // that case, it turns out, the type of the + // closure will also change, because the closure + // also includes references to its upvars as part + // of its type, and those types are resolved at + // the same time. + pending_obligation.stalled_on = + trait_ref_type_vars(selcx, data.to_poly_trait_ref()); + + debug!("process_predicate: pending obligation {:?} now stalled on {:?}", + selcx.infcx().resolve_type_vars_if_possible(obligation), + pending_obligation.stalled_on); + + Ok(None) + } + Err(selection_err) => { + info!("selecting trait `{:?}` at depth {} yielded Err", + data, obligation.recursion_depth); + Err(CodeSelectionError(selection_err)) + } + } + } + + ty::Predicate::Equate(ref binder) => { + match selcx.infcx().equality_predicate(obligation.cause.span, binder) { + Ok(()) => Ok(Some(Vec::new())), + Err(_) => Err(CodeSelectionError(Unimplemented)), + } + } + + ty::Predicate::RegionOutlives(ref binder) => { + match selcx.infcx().region_outlives_predicate(obligation.cause.span, binder) { + Ok(()) => Ok(Some(Vec::new())), + Err(_) => Err(CodeSelectionError(Unimplemented)), + } + } + + ty::Predicate::TypeOutlives(ref binder) => { + // Check if there are higher-ranked regions. + match selcx.tcx().no_late_bound_regions(binder) { + // If there are, inspect the underlying type further. + None => { + // Convert from `Binder>` to `Binder`. + let binder = binder.map_bound_ref(|pred| pred.0); + + // Check if the type has any bound regions. + match selcx.tcx().no_late_bound_regions(&binder) { + // If so, this obligation is an error (for now). Eventually we should be + // able to support additional cases here, like `for<'a> &'a str: 'a`. + None => { + Err(CodeSelectionError(Unimplemented)) + } + // Otherwise, we have something of the form + // `for<'a> T: 'a where 'a not in T`, which we can treat as `T: 'static`. + Some(t_a) => { + register_region_obligation(t_a, ty::ReStatic, + obligation.cause.clone(), + region_obligations); + Ok(Some(vec![])) + } + } + } + // If there aren't, register the obligation. + Some(ty::OutlivesPredicate(t_a, r_b)) => { + register_region_obligation(t_a, r_b, + obligation.cause.clone(), + region_obligations); + Ok(Some(vec![])) + } + } + } + + ty::Predicate::Projection(ref data) => { + let project_obligation = obligation.with(data.clone()); + match project::poly_project_and_unify_type(selcx, &project_obligation) { + Ok(None) => { + pending_obligation.stalled_on = + trait_ref_type_vars(selcx, data.to_poly_trait_ref()); + Ok(None) + } + Ok(v) => Ok(v), + Err(e) => Err(CodeProjectionError(e)) + } + } + + ty::Predicate::ObjectSafe(trait_def_id) => { + if !is_object_safe(selcx.tcx(), trait_def_id) { + Err(CodeSelectionError(Unimplemented)) + } else { + Ok(Some(Vec::new())) + } + } + + ty::Predicate::WellFormed(ty) => { + match ty::wf::obligations(selcx.infcx(), obligation.cause.body_id, + ty, obligation.cause.span) { + None => { + pending_obligation.stalled_on = vec![ty]; + Ok(None) + } + s => Ok(s) + } + } + } +} + +/// For defaulted traits, we use a co-inductive strategy to solve, so +/// that recursion is ok. This routine returns true if the top of the +/// stack (`top_obligation` and `top_data`): +/// - is a defaulted trait, and +/// - it also appears in the backtrace at some position `X`; and, +/// - all the predicates at positions `X..` between `X` an the top are +/// also defaulted traits. +fn coinductive_match<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, + top_obligation: &PredicateObligation<'tcx>, + top_data: &ty::PolyTraitPredicate<'tcx>, + backtrace: &Backtrace>) + -> bool +{ + if selcx.tcx().trait_has_default_impl(top_data.def_id()) { + debug!("coinductive_match: top_data={:?}", top_data); + for bt_obligation in backtrace.clone() { + debug!("coinductive_match: bt_obligation={:?}", bt_obligation); + + // *Everything* in the backtrace must be a defaulted trait. + match bt_obligation.obligation.predicate { + ty::Predicate::Trait(ref data) => { + if !selcx.tcx().trait_has_default_impl(data.def_id()) { + debug!("coinductive_match: trait does not have default impl"); + break; + } + } + _ => { break; } + } + + // And we must find a recursive match. + if bt_obligation.obligation.predicate == top_obligation.predicate { + debug!("coinductive_match: found a match in the backtrace"); + return true; + } + } + } + + false +} + +fn scan_for_cycle<'a,'tcx>(top_obligation: &PredicateObligation<'tcx>, + backtrace: &Backtrace>) + -> Option>> +{ + let mut map = FnvHashMap(); + let all_obligations = + || iter::once(top_obligation) + .chain(backtrace.clone() + .map(|p| &p.obligation)); + for (index, bt_obligation) in all_obligations().enumerate() { + if let Some(&start) = map.get(&bt_obligation.predicate) { + // Found a cycle starting at position `start` and running + // until the current position (`index`). + return Some(all_obligations().skip(start).take(index - start + 1).cloned().collect()); + } else { + map.insert(bt_obligation.predicate.clone(), index); + } + } + None +} + +fn register_region_obligation<'tcx>(t_a: Ty<'tcx>, + r_b: ty::Region, + cause: ObligationCause<'tcx>, + region_obligations: &mut NodeMap>>) +{ + let region_obligation = RegionObligation { sup_type: t_a, + sub_region: r_b, + cause: cause }; + + debug!("register_region_obligation({:?}, cause={:?})", + region_obligation, region_obligation.cause); + + region_obligations.entry(region_obligation.cause.body_id) + .or_insert(vec![]) + .push(region_obligation); + +} + +impl<'tcx> LocalFulfilledPredicates<'tcx> { + pub fn new() -> LocalFulfilledPredicates<'tcx> { + LocalFulfilledPredicates { + set: FnvHashSet() + } + } + + fn is_duplicate_or_add(&mut self, key: &ty::Predicate<'tcx>) -> bool { + // For a `LocalFulfilledPredicates`, if we find a match, we + // don't need to add a read edge to the dep-graph. This is + // because it means that the predicate has already been + // considered by this `FulfillmentContext`, and hence the + // containing task will already have an edge. (Here we are + // assuming each `FulfillmentContext` only gets used from one + // task; but to do otherwise makes no sense) + !self.set.insert(key.clone()) + } +} + +impl<'tcx> GlobalFulfilledPredicates<'tcx> { + pub fn new(dep_graph: DepGraph) -> GlobalFulfilledPredicates<'tcx> { + GlobalFulfilledPredicates { + set: FnvHashSet(), + dep_graph: dep_graph, + } + } + + pub fn check_duplicate(&self, key: &ty::Predicate<'tcx>) -> bool { + if let ty::Predicate::Trait(ref data) = *key { + self.check_duplicate_trait(data) + } else { + false + } + } + + pub fn check_duplicate_trait(&self, data: &ty::PolyTraitPredicate<'tcx>) -> bool { + // For the global predicate registry, when we find a match, it + // may have been computed by some other task, so we want to + // add a read from the node corresponding to the predicate + // processing to make sure we get the transitive dependencies. + if self.set.contains(data) { + debug_assert!(data.is_global()); + self.dep_graph.read(data.dep_node()); + debug!("check_duplicate: global predicate `{:?}` already proved elsewhere", data); + + info!("check_duplicate_trait hit: `{:?}`", data); + + true + } else { + false + } + } + + fn add_if_global(&mut self, key: &ty::Predicate<'tcx>) { + if let ty::Predicate::Trait(ref data) = *key { + // We only add things to the global predicate registry + // after the current task has proved them, and hence + // already has the required read edges, so we don't need + // to add any more edges here. + if data.is_global() { + if self.set.insert(data.clone()) { + debug!("add_if_global: global predicate `{:?}` added", data); + info!("check_duplicate_trait entry: `{:?}`", data); + } + } + } + } +} + +fn to_fulfillment_error<'tcx>( + error: Error, FulfillmentErrorCode<'tcx>>) + -> FulfillmentError<'tcx> +{ + let obligation = error.backtrace.into_iter().next().unwrap().obligation; + FulfillmentError::new(obligation, error.error) +} diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs new file mode 100644 index 00000000000..867bd054fa9 --- /dev/null +++ b/src/librustc/traits/mod.rs @@ -0,0 +1,623 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Trait Resolution. See the Book for more. + +pub use self::SelectionError::*; +pub use self::FulfillmentErrorCode::*; +pub use self::Vtable::*; +pub use self::ObligationCauseCode::*; + +use middle::def_id::DefId; +use middle::free_region::FreeRegionMap; +use ty::subst; +use ty::{self, Ty, TypeFoldable}; +use infer::{self, fixup_err_to_string, InferCtxt}; + +use std::rc::Rc; +use syntax::ast; +use syntax::codemap::{Span, DUMMY_SP}; + +pub use self::error_reporting::TraitErrorKey; +pub use self::error_reporting::recursive_type_with_infinite_size_error; +pub use self::error_reporting::report_fulfillment_errors; +pub use self::error_reporting::report_overflow_error; +pub use self::error_reporting::report_overflow_error_cycle; +pub use self::error_reporting::report_selection_error; +pub use self::error_reporting::report_object_safety_error; +pub use self::coherence::orphan_check; +pub use self::coherence::overlapping_impls; +pub use self::coherence::OrphanCheckErr; +pub use self::fulfill::{FulfillmentContext, GlobalFulfilledPredicates, RegionObligation}; +pub use self::project::{MismatchedProjectionTypes, ProjectionMode}; +pub use self::project::{normalize, Normalized}; +pub use self::object_safety::is_object_safe; +pub use self::object_safety::astconv_object_safety_violations; +pub use self::object_safety::object_safety_violations; +pub use self::object_safety::ObjectSafetyViolation; +pub use self::object_safety::MethodViolationCode; +pub use self::object_safety::is_vtable_safe_method; +pub use self::select::{EvaluationCache, SelectionContext, SelectionCache}; +pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch}; +pub use self::select::{MethodMatchedData}; // intentionally don't export variants +pub use self::specialize::{Overlap, specialization_graph, specializes, translate_substs}; +pub use self::util::elaborate_predicates; +pub use self::util::get_vtable_index_of_object_method; +pub use self::util::trait_ref_for_builtin_bound; +pub use self::util::predicate_for_trait_def; +pub use self::util::supertraits; +pub use self::util::Supertraits; +pub use self::util::supertrait_def_ids; +pub use self::util::SupertraitDefIds; +pub use self::util::transitive_bounds; +pub use self::util::upcast; + +mod coherence; +mod error_reporting; +mod fulfill; +mod project; +mod object_safety; +mod select; +mod specialize; +mod structural_impls; +mod util; + +/// An `Obligation` represents some trait reference (e.g. `int:Eq`) for +/// which the vtable must be found. The process of finding a vtable is +/// called "resolving" the `Obligation`. This process consists of +/// either identifying an `impl` (e.g., `impl Eq for int`) that +/// provides the required vtable, or else finding a bound that is in +/// scope. The eventual result is usually a `Selection` (defined below). +#[derive(Clone, PartialEq, Eq)] +pub struct Obligation<'tcx, T> { + pub cause: ObligationCause<'tcx>, + pub recursion_depth: usize, + pub predicate: T, +} + +pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>; +pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; + +/// Why did we incur this obligation? Used for error reporting. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ObligationCause<'tcx> { + pub span: Span, + + // The id of the fn body that triggered this obligation. This is + // used for region obligations to determine the precise + // environment in which the region obligation should be evaluated + // (in particular, closures can add new assumptions). See the + // field `region_obligations` of the `FulfillmentContext` for more + // information. + pub body_id: ast::NodeId, + + pub code: ObligationCauseCode<'tcx> +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum ObligationCauseCode<'tcx> { + /// Not well classified or should be obvious from span. + MiscObligation, + + /// This is the trait reference from the given projection + SliceOrArrayElem, + + /// This is the trait reference from the given projection + ProjectionWf(ty::ProjectionTy<'tcx>), + + /// In an impl of trait X for type Y, type Y must + /// also implement all supertraits of X. + ItemObligation(DefId), + + /// A type like `&'a T` is WF only if `T: 'a`. + ReferenceOutlivesReferent(Ty<'tcx>), + + /// Obligation incurred due to an object cast. + ObjectCastObligation(/* Object type */ Ty<'tcx>), + + /// Various cases where expressions must be sized/copy/etc: + AssignmentLhsSized, // L = X implies that L is Sized + StructInitializerSized, // S { ... } must be Sized + VariableType(ast::NodeId), // Type of each variable must be Sized + ReturnType, // Return type must be Sized + RepeatVec, // [T,..n] --> T must be Copy + + // Captures of variable the given id by a closure (span is the + // span of the closure) + ClosureCapture(ast::NodeId, Span, ty::BuiltinBound), + + // Types of fields (other than the last) in a struct must be sized. + FieldSized, + + // static items must have `Sync` type + SharedStatic, + + BuiltinDerivedObligation(DerivedObligationCause<'tcx>), + + ImplDerivedObligation(DerivedObligationCause<'tcx>), + + CompareImplMethodObligation, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct DerivedObligationCause<'tcx> { + /// The trait reference of the parent obligation that led to the + /// current obligation. Note that only trait obligations lead to + /// derived obligations, so we just store the trait reference here + /// directly. + parent_trait_ref: ty::PolyTraitRef<'tcx>, + + /// The parent trait had this cause + parent_code: Rc> +} + +pub type Obligations<'tcx, O> = Vec>; +pub type PredicateObligations<'tcx> = Vec>; +pub type TraitObligations<'tcx> = Vec>; + +pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>; + +#[derive(Clone,Debug)] +pub enum SelectionError<'tcx> { + Unimplemented, + OutputTypeParameterMismatch(ty::PolyTraitRef<'tcx>, + ty::PolyTraitRef<'tcx>, + ty::error::TypeError<'tcx>), + TraitNotObjectSafe(DefId), +} + +pub struct FulfillmentError<'tcx> { + pub obligation: PredicateObligation<'tcx>, + pub code: FulfillmentErrorCode<'tcx> +} + +#[derive(Clone)] +pub enum FulfillmentErrorCode<'tcx> { + CodeSelectionError(SelectionError<'tcx>), + CodeProjectionError(MismatchedProjectionTypes<'tcx>), + CodeAmbiguity, +} + +/// When performing resolution, it is typically the case that there +/// can be one of three outcomes: +/// +/// - `Ok(Some(r))`: success occurred with result `r` +/// - `Ok(None)`: could not definitely determine anything, usually due +/// to inconclusive type inference. +/// - `Err(e)`: error `e` occurred +pub type SelectionResult<'tcx, T> = Result, SelectionError<'tcx>>; + +/// Given the successful resolution of an obligation, the `Vtable` +/// indicates where the vtable comes from. Note that while we call this +/// a "vtable", it does not necessarily indicate dynamic dispatch at +/// runtime. `Vtable` instances just tell the compiler where to find +/// methods, but in generic code those methods are typically statically +/// dispatched -- only when an object is constructed is a `Vtable` +/// instance reified into an actual vtable. +/// +/// For example, the vtable may be tied to a specific impl (case A), +/// or it may be relative to some bound that is in scope (case B). +/// +/// +/// ``` +/// impl Clone for Option { ... } // Impl_1 +/// impl Clone for Box { ... } // Impl_2 +/// impl Clone for int { ... } // Impl_3 +/// +/// fn foo(concrete: Option>, +/// param: T, +/// mixed: Option) { +/// +/// // Case A: Vtable points at a specific impl. Only possible when +/// // type is concretely known. If the impl itself has bounded +/// // type parameters, Vtable will carry resolutions for those as well: +/// concrete.clone(); // Vtable(Impl_1, [Vtable(Impl_2, [Vtable(Impl_3)])]) +/// +/// // Case B: Vtable must be provided by caller. This applies when +/// // type is a type parameter. +/// param.clone(); // VtableParam +/// +/// // Case C: A mix of cases A and B. +/// mixed.clone(); // Vtable(Impl_1, [VtableParam]) +/// } +/// ``` +/// +/// ### The type parameter `N` +/// +/// See explanation on `VtableImplData`. +#[derive(Clone)] +pub enum Vtable<'tcx, N> { + /// Vtable identifying a particular impl. + VtableImpl(VtableImplData<'tcx, N>), + + /// Vtable for default trait implementations + /// This carries the information and nested obligations with regards + /// to a default implementation for a trait `Trait`. The nested obligations + /// ensure the trait implementation holds for all the constituent types. + VtableDefaultImpl(VtableDefaultImplData), + + /// Successful resolution to an obligation provided by the caller + /// for some type parameter. The `Vec` represents the + /// obligations incurred from normalizing the where-clause (if + /// any). + VtableParam(Vec), + + /// Virtual calls through an object + VtableObject(VtableObjectData<'tcx>), + + /// Successful resolution for a builtin trait. + VtableBuiltin(VtableBuiltinData), + + /// Vtable automatically generated for a closure. The def ID is the ID + /// of the closure expression. This is a `VtableImpl` in spirit, but the + /// impl is generated by the compiler and does not appear in the source. + VtableClosure(VtableClosureData<'tcx, N>), + + /// Same as above, but for a fn pointer type with the given signature. + VtableFnPointer(ty::Ty<'tcx>), +} + +/// Identifies a particular impl in the source, along with a set of +/// substitutions from the impl's type/lifetime parameters. The +/// `nested` vector corresponds to the nested obligations attached to +/// the impl's type parameters. +/// +/// The type parameter `N` indicates the type used for "nested +/// obligations" that are required by the impl. During type check, this +/// is `Obligation`, as one might expect. During trans, however, this +/// is `()`, because trans only requires a shallow resolution of an +/// impl, and nested obligations are satisfied later. +#[derive(Clone, PartialEq, Eq)] +pub struct VtableImplData<'tcx, N> { + pub impl_def_id: DefId, + pub substs: &'tcx subst::Substs<'tcx>, + pub nested: Vec +} + +#[derive(Clone, PartialEq, Eq)] +pub struct VtableClosureData<'tcx, N> { + pub closure_def_id: DefId, + pub substs: ty::ClosureSubsts<'tcx>, + /// Nested obligations. This can be non-empty if the closure + /// signature contains associated types. + pub nested: Vec +} + +#[derive(Clone)] +pub struct VtableDefaultImplData { + pub trait_def_id: DefId, + pub nested: Vec +} + +#[derive(Clone)] +pub struct VtableBuiltinData { + pub nested: Vec +} + +/// A vtable for some object-safe trait `Foo` automatically derived +/// for the object type `Foo`. +#[derive(PartialEq,Eq,Clone)] +pub struct VtableObjectData<'tcx> { + /// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`. + pub upcast_trait_ref: ty::PolyTraitRef<'tcx>, + + /// The vtable is formed by concatenating together the method lists of + /// the base object trait and all supertraits; this is the start of + /// `upcast_trait_ref`'s methods in that vtable. + pub vtable_base: usize +} + +/// Creates predicate obligations from the generic bounds. +pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>, + generic_bounds: &ty::InstantiatedPredicates<'tcx>) + -> PredicateObligations<'tcx> +{ + util::predicates_for_generics(cause, 0, generic_bounds) +} + +/// Determines whether the type `ty` is known to meet `bound` and +/// returns true if so. Returns false if `ty` either does not meet +/// `bound` or is not known to meet bound (note that this is +/// conservative towards *no impl*, which is the opposite of the +/// `evaluate` methods). +pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, + ty: Ty<'tcx>, + bound: ty::BuiltinBound, + span: Span) + -> bool +{ + debug!("type_known_to_meet_builtin_bound(ty={:?}, bound={:?})", + ty, + bound); + + let cause = ObligationCause::misc(span, ast::DUMMY_NODE_ID); + let obligation = + util::predicate_for_builtin_bound(infcx.tcx, cause, bound, 0, ty); + let obligation = match obligation { + Ok(o) => o, + Err(..) => return false + }; + let result = SelectionContext::new(infcx) + .evaluate_obligation_conservatively(&obligation); + debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} => {:?}", + ty, bound, result); + + if result && (ty.has_infer_types() || ty.has_closure_types()) { + // Because of inference "guessing", selection can sometimes claim + // to succeed while the success requires a guess. To ensure + // this function's result remains infallible, we must confirm + // that guess. While imperfect, I believe this is sound. + + let mut fulfill_cx = FulfillmentContext::new(); + + // We can use a dummy node-id here because we won't pay any mind + // to region obligations that arise (there shouldn't really be any + // anyhow). + let cause = ObligationCause::misc(span, ast::DUMMY_NODE_ID); + + fulfill_cx.register_builtin_bound(infcx, ty, bound, cause); + + // Note: we only assume something is `Copy` if we can + // *definitively* show that it implements `Copy`. Otherwise, + // assume it is move; linear is always ok. + match fulfill_cx.select_all_or_error(infcx) { + Ok(()) => { + debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} success", + ty, + bound); + true + } + Err(e) => { + debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} errors={:?}", + ty, + bound, + e); + false + } + } + } else { + result + } +} + +// FIXME: this is gonna need to be removed ... +/// Normalizes the parameter environment, reporting errors if they occur. +pub fn normalize_param_env_or_error<'a,'tcx>(unnormalized_env: ty::ParameterEnvironment<'a,'tcx>, + cause: ObligationCause<'tcx>) + -> ty::ParameterEnvironment<'a,'tcx> +{ + // I'm not wild about reporting errors here; I'd prefer to + // have the errors get reported at a defined place (e.g., + // during typeck). Instead I have all parameter + // environments, in effect, going through this function + // and hence potentially reporting errors. This ensurse of + // course that we never forget to normalize (the + // alternative seemed like it would involve a lot of + // manual invocations of this fn -- and then we'd have to + // deal with the errors at each of those sites). + // + // In any case, in practice, typeck constructs all the + // parameter environments once for every fn as it goes, + // and errors will get reported then; so after typeck we + // can be sure that no errors should occur. + + let tcx = unnormalized_env.tcx; + let span = cause.span; + let body_id = cause.body_id; + + debug!("normalize_param_env_or_error(unnormalized_env={:?})", + unnormalized_env); + + let predicates: Vec<_> = + util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.clone()) + .filter(|p| !p.is_global()) // (*) + .collect(); + + // (*) Any predicate like `i32: Trait` or whatever doesn't + // need to be in the *environment* to be proven, so screen those + // out. This is important for the soundness of inter-fn + // caching. Note though that we should probably check that these + // predicates hold at the point where the environment is + // constructed, but I am not currently doing so out of laziness. + // -nmatsakis + + debug!("normalize_param_env_or_error: elaborated-predicates={:?}", + predicates); + + let elaborated_env = unnormalized_env.with_caller_bounds(predicates); + + let infcx = infer::new_infer_ctxt(tcx, + &tcx.tables, + Some(elaborated_env), + ProjectionMode::AnyFinal); + let predicates = match fully_normalize(&infcx, + cause, + &infcx.parameter_environment.caller_bounds) { + Ok(predicates) => predicates, + Err(errors) => { + report_fulfillment_errors(&infcx, &errors); + return infcx.parameter_environment; // an unnormalized env is better than nothing + } + }; + + debug!("normalize_param_env_or_error: normalized predicates={:?}", + predicates); + + let free_regions = FreeRegionMap::new(); + infcx.resolve_regions_and_report_errors(&free_regions, body_id); + let predicates = match infcx.fully_resolve(&predicates) { + Ok(predicates) => predicates, + Err(fixup_err) => { + // If we encounter a fixup error, it means that some type + // variable wound up unconstrained. I actually don't know + // if this can happen, and I certainly don't expect it to + // happen often, but if it did happen it probably + // represents a legitimate failure due to some kind of + // unconstrained variable, and it seems better not to ICE, + // all things considered. + let err_msg = fixup_err_to_string(fixup_err); + tcx.sess.span_err(span, &err_msg); + return infcx.parameter_environment; // an unnormalized env is better than nothing + } + }; + + debug!("normalize_param_env_or_error: resolved predicates={:?}", + predicates); + + infcx.parameter_environment.with_caller_bounds(predicates) +} + +pub fn fully_normalize<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, + cause: ObligationCause<'tcx>, + value: &T) + -> Result>> + where T : TypeFoldable<'tcx> +{ + debug!("fully_normalize(value={:?})", value); + + let mut selcx = &mut SelectionContext::new(infcx); + // FIXME (@jroesch) ISSUE 26721 + // I'm not sure if this is a bug or not, needs further investigation. + // It appears that by reusing the fulfillment_cx here we incur more + // obligations and later trip an asssertion on regionck.rs line 337. + // + // The two possibilities I see is: + // - normalization is not actually fully happening and we + // have a bug else where + // - we are adding a duplicate bound into the list causing + // its size to change. + // + // I think we should probably land this refactor and then come + // back to this is a follow-up patch. + let mut fulfill_cx = FulfillmentContext::new(); + + let Normalized { value: normalized_value, obligations } = + project::normalize(selcx, cause, value); + debug!("fully_normalize: normalized_value={:?} obligations={:?}", + normalized_value, + obligations); + for obligation in obligations { + fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation); + } + + debug!("fully_normalize: select_all_or_error start"); + match fulfill_cx.select_all_or_error(infcx) { + Ok(()) => { } + Err(e) => { + debug!("fully_normalize: error={:?}", e); + return Err(e); + } + } + debug!("fully_normalize: select_all_or_error complete"); + let resolved_value = infcx.resolve_type_vars_if_possible(&normalized_value); + debug!("fully_normalize: resolved_value={:?}", resolved_value); + Ok(resolved_value) +} + +impl<'tcx,O> Obligation<'tcx,O> { + pub fn new(cause: ObligationCause<'tcx>, + trait_ref: O) + -> Obligation<'tcx, O> + { + Obligation { cause: cause, + recursion_depth: 0, + predicate: trait_ref } + } + + fn with_depth(cause: ObligationCause<'tcx>, + recursion_depth: usize, + trait_ref: O) + -> Obligation<'tcx, O> + { + Obligation { cause: cause, + recursion_depth: recursion_depth, + predicate: trait_ref } + } + + pub fn misc(span: Span, body_id: ast::NodeId, trait_ref: O) -> Obligation<'tcx, O> { + Obligation::new(ObligationCause::misc(span, body_id), trait_ref) + } + + pub fn with

(&self, value: P) -> Obligation<'tcx,P> { + Obligation { cause: self.cause.clone(), + recursion_depth: self.recursion_depth, + predicate: value } + } +} + +impl<'tcx> ObligationCause<'tcx> { + pub fn new(span: Span, + body_id: ast::NodeId, + code: ObligationCauseCode<'tcx>) + -> ObligationCause<'tcx> { + ObligationCause { span: span, body_id: body_id, code: code } + } + + pub fn misc(span: Span, body_id: ast::NodeId) -> ObligationCause<'tcx> { + ObligationCause { span: span, body_id: body_id, code: MiscObligation } + } + + pub fn dummy() -> ObligationCause<'tcx> { + ObligationCause { span: DUMMY_SP, body_id: 0, code: MiscObligation } + } +} + +impl<'tcx, N> Vtable<'tcx, N> { + pub fn nested_obligations(self) -> Vec { + match self { + VtableImpl(i) => i.nested, + VtableParam(n) => n, + VtableBuiltin(i) => i.nested, + VtableDefaultImpl(d) => d.nested, + VtableClosure(c) => c.nested, + VtableObject(_) | VtableFnPointer(..) => vec![] + } + } + + pub fn map(self, f: F) -> Vtable<'tcx, M> where F: FnMut(N) -> M { + match self { + VtableImpl(i) => VtableImpl(VtableImplData { + impl_def_id: i.impl_def_id, + substs: i.substs, + nested: i.nested.into_iter().map(f).collect() + }), + VtableParam(n) => VtableParam(n.into_iter().map(f).collect()), + VtableBuiltin(i) => VtableBuiltin(VtableBuiltinData { + nested: i.nested.into_iter().map(f).collect() + }), + VtableObject(o) => VtableObject(o), + VtableDefaultImpl(d) => VtableDefaultImpl(VtableDefaultImplData { + trait_def_id: d.trait_def_id, + nested: d.nested.into_iter().map(f).collect() + }), + VtableFnPointer(f) => VtableFnPointer(f), + VtableClosure(c) => VtableClosure(VtableClosureData { + closure_def_id: c.closure_def_id, + substs: c.substs, + nested: c.nested.into_iter().map(f).collect(), + }) + } + } +} + +impl<'tcx> FulfillmentError<'tcx> { + fn new(obligation: PredicateObligation<'tcx>, + code: FulfillmentErrorCode<'tcx>) + -> FulfillmentError<'tcx> + { + FulfillmentError { obligation: obligation, code: code } + } +} + +impl<'tcx> TraitObligation<'tcx> { + fn self_ty(&self) -> ty::Binder> { + ty::Binder(self.predicate.skip_binder().self_ty()) + } +} diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs new file mode 100644 index 00000000000..7cd2ac5938d --- /dev/null +++ b/src/librustc/traits/object_safety.rs @@ -0,0 +1,379 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! "Object safety" refers to the ability for a trait to be converted +//! to an object. In general, traits may only be converted to an +//! object if all of their methods meet certain criteria. In particular, +//! they must: +//! +//! - have a suitable receiver from which we can extract a vtable; +//! - not reference the erased type `Self` except for in this receiver; +//! - not have generic type parameters + +use super::supertraits; +use super::elaborate_predicates; + +use middle::def_id::DefId; +use ty::subst::{self, SelfSpace, TypeSpace}; +use traits; +use ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; +use std::rc::Rc; +use syntax::ast; + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum ObjectSafetyViolation<'tcx> { + /// Self : Sized declared on the trait + SizedSelf, + + /// Supertrait reference references `Self` an in illegal location + /// (e.g. `trait Foo : Bar`) + SupertraitSelf, + + /// Method has something illegal + Method(Rc>, MethodViolationCode), +} + +/// Reasons a method might not be object-safe. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum MethodViolationCode { + /// e.g., `fn foo()` + StaticMethod, + + /// e.g., `fn foo(&self, x: Self)` or `fn foo(&self) -> Self` + ReferencesSelf, + + /// e.g., `fn foo()` + Generic, +} + +pub fn is_object_safe<'tcx>(tcx: &TyCtxt<'tcx>, + trait_def_id: DefId) + -> bool +{ + // Because we query yes/no results frequently, we keep a cache: + let def = tcx.lookup_trait_def(trait_def_id); + + let result = def.object_safety().unwrap_or_else(|| { + let result = object_safety_violations(tcx, trait_def_id).is_empty(); + + // Record just a yes/no result in the cache; this is what is + // queried most frequently. Note that this may overwrite a + // previous result, but always with the same thing. + def.set_object_safety(result); + + result + }); + + debug!("is_object_safe({:?}) = {}", trait_def_id, result); + + result +} + +/// Returns the object safety violations that affect +/// astconv - currently, Self in supertraits. This is needed +/// because `object_safety_violations` can't be used during +/// type collection. +pub fn astconv_object_safety_violations<'tcx>(tcx: &TyCtxt<'tcx>, + trait_def_id: DefId) + -> Vec> +{ + let mut violations = vec![]; + + if supertraits_reference_self(tcx, trait_def_id) { + violations.push(ObjectSafetyViolation::SupertraitSelf); + } + + debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}", + trait_def_id, + violations); + + violations +} + +pub fn object_safety_violations<'tcx>(tcx: &TyCtxt<'tcx>, + trait_def_id: DefId) + -> Vec> +{ + traits::supertrait_def_ids(tcx, trait_def_id) + .flat_map(|def_id| object_safety_violations_for_trait(tcx, def_id)) + .collect() +} + +fn object_safety_violations_for_trait<'tcx>(tcx: &TyCtxt<'tcx>, + trait_def_id: DefId) + -> Vec> +{ + // Check methods for violations. + let mut violations: Vec<_> = + tcx.trait_items(trait_def_id).iter() + .filter_map(|item| { + match *item { + ty::MethodTraitItem(ref m) => { + object_safety_violation_for_method(tcx, trait_def_id, &m) + .map(|code| ObjectSafetyViolation::Method(m.clone(), code)) + } + _ => None, + } + }) + .collect(); + + // Check the trait itself. + if trait_has_sized_self(tcx, trait_def_id) { + violations.push(ObjectSafetyViolation::SizedSelf); + } + if supertraits_reference_self(tcx, trait_def_id) { + violations.push(ObjectSafetyViolation::SupertraitSelf); + } + + debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}", + trait_def_id, + violations); + + violations +} + +pub fn supertraits_reference_self<'tcx>(tcx: &TyCtxt<'tcx>, + trait_def_id: DefId) + -> bool +{ + let trait_def = tcx.lookup_trait_def(trait_def_id); + let trait_ref = trait_def.trait_ref.clone(); + let trait_ref = trait_ref.to_poly_trait_ref(); + let predicates = tcx.lookup_super_predicates(trait_def_id); + predicates + .predicates + .into_iter() + .map(|predicate| predicate.subst_supertrait(tcx, &trait_ref)) + .any(|predicate| { + match predicate { + ty::Predicate::Trait(ref data) => { + // In the case of a trait predicate, we can skip the "self" type. + data.0.trait_ref.substs.types.get_slice(TypeSpace) + .iter() + .cloned() + .any(|t| t.has_self_ty()) + } + ty::Predicate::Projection(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | + ty::Predicate::TypeOutlives(..) | + ty::Predicate::RegionOutlives(..) | + ty::Predicate::Equate(..) => { + false + } + } + }) +} + +fn trait_has_sized_self<'tcx>(tcx: &TyCtxt<'tcx>, + trait_def_id: DefId) + -> bool +{ + let trait_def = tcx.lookup_trait_def(trait_def_id); + let trait_predicates = tcx.lookup_predicates(trait_def_id); + generics_require_sized_self(tcx, &trait_def.generics, &trait_predicates) +} + +fn generics_require_sized_self<'tcx>(tcx: &TyCtxt<'tcx>, + generics: &ty::Generics<'tcx>, + predicates: &ty::GenericPredicates<'tcx>) + -> bool +{ + let sized_def_id = match tcx.lang_items.sized_trait() { + Some(def_id) => def_id, + None => { return false; /* No Sized trait, can't require it! */ } + }; + + // Search for a predicate like `Self : Sized` amongst the trait bounds. + let free_substs = tcx.construct_free_substs(generics, + tcx.region_maps.node_extent(ast::DUMMY_NODE_ID)); + let predicates = predicates.instantiate(tcx, &free_substs).predicates.into_vec(); + elaborate_predicates(tcx, predicates) + .any(|predicate| { + match predicate { + ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => { + trait_pred.0.self_ty().is_self() + } + ty::Predicate::Projection(..) | + ty::Predicate::Trait(..) | + ty::Predicate::Equate(..) | + ty::Predicate::RegionOutlives(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | + ty::Predicate::TypeOutlives(..) => { + false + } + } + }) +} + +/// Returns `Some(_)` if this method makes the containing trait not object safe. +fn object_safety_violation_for_method<'tcx>(tcx: &TyCtxt<'tcx>, + trait_def_id: DefId, + method: &ty::Method<'tcx>) + -> Option +{ + // Any method that has a `Self : Sized` requisite is otherwise + // exempt from the regulations. + if generics_require_sized_self(tcx, &method.generics, &method.predicates) { + return None; + } + + virtual_call_violation_for_method(tcx, trait_def_id, method) +} + +/// We say a method is *vtable safe* if it can be invoked on a trait +/// object. Note that object-safe traits can have some +/// non-vtable-safe methods, so long as they require `Self:Sized` or +/// otherwise ensure that they cannot be used when `Self=Trait`. +pub fn is_vtable_safe_method<'tcx>(tcx: &TyCtxt<'tcx>, + trait_def_id: DefId, + method: &ty::Method<'tcx>) + -> bool +{ + virtual_call_violation_for_method(tcx, trait_def_id, method).is_none() +} + +/// Returns `Some(_)` if this method cannot be called on a trait +/// object; this does not necessarily imply that the enclosing trait +/// is not object safe, because the method might have a where clause +/// `Self:Sized`. +fn virtual_call_violation_for_method<'tcx>(tcx: &TyCtxt<'tcx>, + trait_def_id: DefId, + method: &ty::Method<'tcx>) + -> Option +{ + // The method's first parameter must be something that derefs (or + // autorefs) to `&self`. For now, we only accept `self`, `&self` + // and `Box`. + match method.explicit_self { + ty::ExplicitSelfCategory::Static => { + return Some(MethodViolationCode::StaticMethod); + } + + ty::ExplicitSelfCategory::ByValue | + ty::ExplicitSelfCategory::ByReference(..) | + ty::ExplicitSelfCategory::ByBox => { + } + } + + // The `Self` type is erased, so it should not appear in list of + // arguments or return type apart from the receiver. + let ref sig = method.fty.sig; + for &input_ty in &sig.0.inputs[1..] { + if contains_illegal_self_type_reference(tcx, trait_def_id, input_ty) { + return Some(MethodViolationCode::ReferencesSelf); + } + } + if let ty::FnConverging(result_type) = sig.0.output { + if contains_illegal_self_type_reference(tcx, trait_def_id, result_type) { + return Some(MethodViolationCode::ReferencesSelf); + } + } + + // We can't monomorphize things like `fn foo(...)`. + if !method.generics.types.is_empty_in(subst::FnSpace) { + return Some(MethodViolationCode::Generic); + } + + None +} + +fn contains_illegal_self_type_reference<'tcx>(tcx: &TyCtxt<'tcx>, + trait_def_id: DefId, + ty: Ty<'tcx>) + -> bool +{ + // This is somewhat subtle. In general, we want to forbid + // references to `Self` in the argument and return types, + // since the value of `Self` is erased. However, there is one + // exception: it is ok to reference `Self` in order to access + // an associated type of the current trait, since we retain + // the value of those associated types in the object type + // itself. + // + // ```rust + // trait SuperTrait { + // type X; + // } + // + // trait Trait : SuperTrait { + // type Y; + // fn foo(&self, x: Self) // bad + // fn foo(&self) -> Self // bad + // fn foo(&self) -> Option // bad + // fn foo(&self) -> Self::Y // OK, desugars to next example + // fn foo(&self) -> ::Y // OK + // fn foo(&self) -> Self::X // OK, desugars to next example + // fn foo(&self) -> ::X // OK + // } + // ``` + // + // However, it is not as simple as allowing `Self` in a projected + // type, because there are illegal ways to use `Self` as well: + // + // ```rust + // trait Trait : SuperTrait { + // ... + // fn foo(&self) -> ::X; + // } + // ``` + // + // Here we will not have the type of `X` recorded in the + // object type, and we cannot resolve `Self as SomeOtherTrait` + // without knowing what `Self` is. + + let mut supertraits: Option>> = None; + let mut error = false; + ty.maybe_walk(|ty| { + match ty.sty { + ty::TyParam(ref param_ty) => { + if param_ty.space == SelfSpace { + error = true; + } + + false // no contained types to walk + } + + ty::TyProjection(ref data) => { + // This is a projected type `::X`. + + // Compute supertraits of current trait lazily. + if supertraits.is_none() { + let trait_def = tcx.lookup_trait_def(trait_def_id); + let trait_ref = ty::Binder(trait_def.trait_ref.clone()); + supertraits = Some(traits::supertraits(tcx, trait_ref).collect()); + } + + // Determine whether the trait reference `Foo as + // SomeTrait` is in fact a supertrait of the + // current trait. In that case, this type is + // legal, because the type `X` will be specified + // in the object type. Note that we can just use + // direct equality here because all of these types + // are part of the formal parameter listing, and + // hence there should be no inference variables. + let projection_trait_ref = ty::Binder(data.trait_ref.clone()); + let is_supertrait_of_current_trait = + supertraits.as_ref().unwrap().contains(&projection_trait_ref); + + if is_supertrait_of_current_trait { + false // do not walk contained types, do not report error, do collect $200 + } else { + true // DO walk contained types, POSSIBLY reporting an error + } + } + + _ => true, // walk contained types, if any + } + }); + + error +} diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs new file mode 100644 index 00000000000..3adaf5fa6bb --- /dev/null +++ b/src/librustc/traits/project.rs @@ -0,0 +1,1164 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Code for projecting associated types out of trait references. + +use super::elaborate_predicates; +use super::report_overflow_error; +use super::specialization_graph; +use super::translate_substs; +use super::Obligation; +use super::ObligationCause; +use super::PredicateObligation; +use super::SelectionContext; +use super::SelectionError; +use super::VtableClosureData; +use super::VtableImplData; +use super::util; + +use middle::def_id::DefId; +use infer::{self, TypeOrigin}; +use ty::subst::Subst; +use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt}; +use ty::fold::{TypeFoldable, TypeFolder}; +use syntax::parse::token; +use syntax::ast; +use util::common::FN_OUTPUT_NAME; + +use std::rc::Rc; + +/// Depending on the stage of compilation, we want projection to be +/// more or less conservative. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ProjectionMode { + /// FIXME (#32205) + /// At coherence-checking time, we're still constructing the + /// specialization graph, and thus we only project project + /// non-`default` associated types that are defined directly in + /// the applicable impl. (This behavior should be improved over + /// time, to allow for successful projections modulo cycles + /// between different impls). + /// + /// Here's an example that will fail due to the restriction: + /// + /// ``` + /// trait Assoc { + /// type Output; + /// } + /// + /// impl Assoc for T { + /// type Output = bool; + /// } + /// + /// impl Assoc for u8 {} // <- inherits the non-default type from above + /// + /// trait Foo {} + /// impl Foo for u32 {} + /// impl Foo for ::Output {} // <- this projection will fail + /// ``` + /// + /// The projection would succeed if `Output` had been defined + /// directly in the impl for `u8`. + Topmost, + + /// At type-checking time, we refuse to project any associated + /// type that is marked `default`. Non-`default` ("final") types + /// are always projected. This is necessary in general for + /// soundness of specialization. However, we *could* allow + /// projections in fully-monomorphic cases. We choose not to, + /// because we prefer for `default type` to force the type + /// definition to be treated abstractly by any consumers of the + /// impl. Concretely, that means that the following example will + /// fail to compile: + /// + /// ``` + /// trait Assoc { + /// type Output; + /// } + /// + /// impl Assoc for T { + /// default type Output = bool; + /// } + /// + /// fn main() { + /// let <() as Assoc>::Output = true; + /// } + AnyFinal, + + /// At trans time, all projections will succeed. + Any, +} + +impl ProjectionMode { + pub fn is_topmost(&self) -> bool { + match *self { + ProjectionMode::Topmost => true, + _ => false, + } + } + + pub fn is_any_final(&self) -> bool { + match *self { + ProjectionMode::AnyFinal => true, + _ => false, + } + } + + pub fn is_any(&self) -> bool { + match *self { + ProjectionMode::Any => true, + _ => false, + } + } +} + + +pub type PolyProjectionObligation<'tcx> = + Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>; + +pub type ProjectionObligation<'tcx> = + Obligation<'tcx, ty::ProjectionPredicate<'tcx>>; + +pub type ProjectionTyObligation<'tcx> = + Obligation<'tcx, ty::ProjectionTy<'tcx>>; + +/// When attempting to resolve `::Name` ... +#[derive(Debug)] +pub enum ProjectionTyError<'tcx> { + /// ...we found multiple sources of information and couldn't resolve the ambiguity. + TooManyCandidates, + + /// ...an error occurred matching `T : TraitRef` + TraitSelectionError(SelectionError<'tcx>), +} + +#[derive(Clone)] +pub struct MismatchedProjectionTypes<'tcx> { + pub err: ty::error::TypeError<'tcx> +} + +#[derive(PartialEq, Eq, Debug)] +enum ProjectionTyCandidate<'tcx> { + // from a where-clause in the env or object type + ParamEnv(ty::PolyProjectionPredicate<'tcx>), + + // from the definition of `Trait` when you have something like <::B as Trait2>::C + TraitDef(ty::PolyProjectionPredicate<'tcx>), + + // defined in an impl + Impl(VtableImplData<'tcx, PredicateObligation<'tcx>>), + + // closure return type + Closure(VtableClosureData<'tcx, PredicateObligation<'tcx>>), + + // fn pointer return type + FnPointer(Ty<'tcx>), +} + +struct ProjectionTyCandidateSet<'tcx> { + vec: Vec>, + ambiguous: bool +} + +/// Evaluates constraints of the form: +/// +/// for<...> ::U == V +/// +/// If successful, this may result in additional obligations. +pub fn poly_project_and_unify_type<'cx,'tcx>( + selcx: &mut SelectionContext<'cx,'tcx>, + obligation: &PolyProjectionObligation<'tcx>) + -> Result>>, MismatchedProjectionTypes<'tcx>> +{ + debug!("poly_project_and_unify_type(obligation={:?})", + obligation); + + let infcx = selcx.infcx(); + infcx.commit_if_ok(|snapshot| { + let (skol_predicate, skol_map) = + infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot); + + let skol_obligation = obligation.with(skol_predicate); + match project_and_unify_type(selcx, &skol_obligation) { + Ok(result) => { + match infcx.leak_check(&skol_map, snapshot) { + Ok(()) => Ok(infcx.plug_leaks(skol_map, snapshot, &result)), + Err(e) => Err(MismatchedProjectionTypes { err: e }), + } + } + Err(e) => { + Err(e) + } + } + }) +} + +/// Evaluates constraints of the form: +/// +/// ::U == V +/// +/// If successful, this may result in additional obligations. +fn project_and_unify_type<'cx,'tcx>( + selcx: &mut SelectionContext<'cx,'tcx>, + obligation: &ProjectionObligation<'tcx>) + -> Result>>, MismatchedProjectionTypes<'tcx>> +{ + debug!("project_and_unify_type(obligation={:?})", + obligation); + + let Normalized { value: normalized_ty, obligations } = + match opt_normalize_projection_type(selcx, + obligation.predicate.projection_ty.clone(), + obligation.cause.clone(), + obligation.recursion_depth) { + Some(n) => n, + None => { + consider_unification_despite_ambiguity(selcx, obligation); + return Ok(None); + } + }; + + debug!("project_and_unify_type: normalized_ty={:?} obligations={:?}", + normalized_ty, + obligations); + + let infcx = selcx.infcx(); + let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); + match infer::mk_eqty(infcx, true, origin, normalized_ty, obligation.predicate.ty) { + Ok(()) => Ok(Some(obligations)), + Err(err) => Err(MismatchedProjectionTypes { err: err }), + } +} + +fn consider_unification_despite_ambiguity<'cx,'tcx>(selcx: &mut SelectionContext<'cx,'tcx>, + obligation: &ProjectionObligation<'tcx>) { + debug!("consider_unification_despite_ambiguity(obligation={:?})", + obligation); + + let def_id = obligation.predicate.projection_ty.trait_ref.def_id; + match selcx.tcx().lang_items.fn_trait_kind(def_id) { + Some(_) => { } + None => { return; } + } + + let infcx = selcx.infcx(); + let self_ty = obligation.predicate.projection_ty.trait_ref.self_ty(); + let self_ty = infcx.shallow_resolve(self_ty); + debug!("consider_unification_despite_ambiguity: self_ty.sty={:?}", + self_ty.sty); + match self_ty.sty { + ty::TyClosure(closure_def_id, ref substs) => { + let closure_typer = selcx.closure_typer(); + let closure_type = closure_typer.closure_type(closure_def_id, substs); + let ty::Binder((_, ret_type)) = + util::closure_trait_ref_and_return_type(infcx.tcx, + def_id, + self_ty, + &closure_type.sig, + util::TupleArgumentsFlag::No); + // We don't have to normalize the return type here - this is only + // reached for TyClosure: Fn inputs where the closure kind is + // still unknown, which should only occur in typeck where the + // closure type is already normalized. + let (ret_type, _) = + infcx.replace_late_bound_regions_with_fresh_var( + obligation.cause.span, + infer::AssocTypeProjection(obligation.predicate.projection_ty.item_name), + &ty::Binder(ret_type)); + + debug!("consider_unification_despite_ambiguity: ret_type={:?}", + ret_type); + let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); + let obligation_ty = obligation.predicate.ty; + match infer::mk_eqty(infcx, true, origin, obligation_ty, ret_type) { + Ok(()) => { } + Err(_) => { /* ignore errors */ } + } + } + _ => { } + } +} + +/// Normalizes any associated type projections in `value`, replacing +/// them with a fully resolved type where possible. The return value +/// combines the normalized result and any additional obligations that +/// were incurred as result. +pub fn normalize<'a,'b,'tcx,T>(selcx: &'a mut SelectionContext<'b,'tcx>, + cause: ObligationCause<'tcx>, + value: &T) + -> Normalized<'tcx, T> + where T : TypeFoldable<'tcx> +{ + normalize_with_depth(selcx, cause, 0, value) +} + +/// As `normalize`, but with a custom depth. +pub fn normalize_with_depth<'a,'b,'tcx,T>(selcx: &'a mut SelectionContext<'b,'tcx>, + cause: ObligationCause<'tcx>, + depth: usize, + value: &T) + -> Normalized<'tcx, T> + where T : TypeFoldable<'tcx> +{ + let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, depth); + let result = normalizer.fold(value); + + Normalized { + value: result, + obligations: normalizer.obligations, + } +} + +struct AssociatedTypeNormalizer<'a,'b:'a,'tcx:'b> { + selcx: &'a mut SelectionContext<'b,'tcx>, + cause: ObligationCause<'tcx>, + obligations: Vec>, + depth: usize, +} + +impl<'a,'b,'tcx> AssociatedTypeNormalizer<'a,'b,'tcx> { + fn new(selcx: &'a mut SelectionContext<'b,'tcx>, + cause: ObligationCause<'tcx>, + depth: usize) + -> AssociatedTypeNormalizer<'a,'b,'tcx> + { + AssociatedTypeNormalizer { + selcx: selcx, + cause: cause, + obligations: vec!(), + depth: depth, + } + } + + fn fold>(&mut self, value: &T) -> T { + let value = self.selcx.infcx().resolve_type_vars_if_possible(value); + + if !value.has_projection_types() { + value.clone() + } else { + value.fold_with(self) + } + } +} + +impl<'a,'b,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'b,'tcx> { + fn tcx(&self) -> &TyCtxt<'tcx> { + self.selcx.tcx() + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + // We don't want to normalize associated types that occur inside of region + // binders, because they may contain bound regions, and we can't cope with that. + // + // Example: + // + // for<'a> fn(>::A) + // + // Instead of normalizing `>::A` here, we'll + // normalize it when we instantiate those bound regions (which + // should occur eventually). + + let ty = ty.super_fold_with(self); + match ty.sty { + ty::TyProjection(ref data) if !data.has_escaping_regions() => { // (*) + + // (*) This is kind of hacky -- we need to be able to + // handle normalization within binders because + // otherwise we wind up a need to normalize when doing + // trait matching (since you can have a trait + // obligation like `for<'a> T::B : Fn(&'a int)`), but + // we can't normalize with bound regions in scope. So + // far now we just ignore binders but only normalize + // if all bound regions are gone (and then we still + // have to renormalize whenever we instantiate a + // binder). It would be better to normalize in a + // binding-aware fashion. + + let Normalized { value: ty, obligations } = + normalize_projection_type(self.selcx, + data.clone(), + self.cause.clone(), + self.depth); + self.obligations.extend(obligations); + ty + } + + _ => { + ty + } + } + } +} + +#[derive(Clone)] +pub struct Normalized<'tcx,T> { + pub value: T, + pub obligations: Vec>, +} + +pub type NormalizedTy<'tcx> = Normalized<'tcx, Ty<'tcx>>; + +impl<'tcx,T> Normalized<'tcx,T> { + pub fn with(self, value: U) -> Normalized<'tcx,U> { + Normalized { value: value, obligations: self.obligations } + } +} + +/// The guts of `normalize`: normalize a specific projection like `::Item`. The result is always a type (and possibly +/// additional obligations). If ambiguity arises, which implies that +/// there are unresolved type variables in the projection, we will +/// substitute a fresh type variable `$X` and generate a new +/// obligation `::Item == $X` for later. +pub fn normalize_projection_type<'a,'b,'tcx>( + selcx: &'a mut SelectionContext<'b,'tcx>, + projection_ty: ty::ProjectionTy<'tcx>, + cause: ObligationCause<'tcx>, + depth: usize) + -> NormalizedTy<'tcx> +{ + opt_normalize_projection_type(selcx, projection_ty.clone(), cause.clone(), depth) + .unwrap_or_else(move || { + // if we bottom out in ambiguity, create a type variable + // and a deferred predicate to resolve this when more type + // information is available. + + let ty_var = selcx.infcx().next_ty_var(); + let projection = ty::Binder(ty::ProjectionPredicate { + projection_ty: projection_ty, + ty: ty_var + }); + let obligation = Obligation::with_depth( + cause, depth + 1, projection.to_predicate()); + Normalized { + value: ty_var, + obligations: vec!(obligation) + } + }) +} + +/// The guts of `normalize`: normalize a specific projection like `::Item`. The result is always a type (and possibly +/// additional obligations). Returns `None` in the case of ambiguity, +/// which indicates that there are unbound type variables. +fn opt_normalize_projection_type<'a,'b,'tcx>( + selcx: &'a mut SelectionContext<'b,'tcx>, + projection_ty: ty::ProjectionTy<'tcx>, + cause: ObligationCause<'tcx>, + depth: usize) + -> Option> +{ + debug!("normalize_projection_type(\ + projection_ty={:?}, \ + depth={})", + projection_ty, + depth); + + let obligation = Obligation::with_depth(cause.clone(), depth, projection_ty.clone()); + match project_type(selcx, &obligation) { + Ok(ProjectedTy::Progress(projected_ty, mut obligations)) => { + // if projection succeeded, then what we get out of this + // is also non-normalized (consider: it was derived from + // an impl, where-clause etc) and hence we must + // re-normalize it + + debug!("normalize_projection_type: projected_ty={:?} depth={} obligations={:?}", + projected_ty, + depth, + obligations); + + if projected_ty.has_projection_types() { + let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, depth+1); + let normalized_ty = normalizer.fold(&projected_ty); + + debug!("normalize_projection_type: normalized_ty={:?} depth={}", + normalized_ty, + depth); + + obligations.extend(normalizer.obligations); + Some(Normalized { + value: normalized_ty, + obligations: obligations, + }) + } else { + Some(Normalized { + value: projected_ty, + obligations: obligations, + }) + } + } + Ok(ProjectedTy::NoProgress(projected_ty)) => { + debug!("normalize_projection_type: projected_ty={:?} no progress", + projected_ty); + Some(Normalized { + value: projected_ty, + obligations: vec!() + }) + } + Err(ProjectionTyError::TooManyCandidates) => { + debug!("normalize_projection_type: too many candidates"); + None + } + Err(ProjectionTyError::TraitSelectionError(_)) => { + debug!("normalize_projection_type: ERROR"); + // if we got an error processing the `T as Trait` part, + // just return `ty::err` but add the obligation `T : + // Trait`, which when processed will cause the error to be + // reported later + + Some(normalize_to_error(selcx, projection_ty, cause, depth)) + } + } +} + +/// If we are projecting `::Item`, but `T: Trait` does not +/// hold. In various error cases, we cannot generate a valid +/// normalized projection. Therefore, we create an inference variable +/// return an associated obligation that, when fulfilled, will lead to +/// an error. +/// +/// Note that we used to return `TyError` here, but that was quite +/// dubious -- the premise was that an error would *eventually* be +/// reported, when the obligation was processed. But in general once +/// you see a `TyError` you are supposed to be able to assume that an +/// error *has been* reported, so that you can take whatever heuristic +/// paths you want to take. To make things worse, it was possible for +/// cycles to arise, where you basically had a setup like ` +/// as Trait>::Foo == $0`. Here, normalizing ` as +/// Trait>::Foo> to `[type error]` would lead to an obligation of +/// ` as Trait>::Foo`. We are supposed to report +/// an error for this obligation, but we legitimately should not, +/// because it contains `[type error]`. Yuck! (See issue #29857 for +/// one case where this arose.) +fn normalize_to_error<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, + projection_ty: ty::ProjectionTy<'tcx>, + cause: ObligationCause<'tcx>, + depth: usize) + -> NormalizedTy<'tcx> +{ + let trait_ref = projection_ty.trait_ref.to_poly_trait_ref(); + let trait_obligation = Obligation { cause: cause, + recursion_depth: depth, + predicate: trait_ref.to_predicate() }; + let new_value = selcx.infcx().next_ty_var(); + Normalized { + value: new_value, + obligations: vec!(trait_obligation) + } +} + +enum ProjectedTy<'tcx> { + Progress(Ty<'tcx>, Vec>), + NoProgress(Ty<'tcx>), +} + +/// Compute the result of a projection type (if we can). +fn project_type<'cx,'tcx>( + selcx: &mut SelectionContext<'cx,'tcx>, + obligation: &ProjectionTyObligation<'tcx>) + -> Result, ProjectionTyError<'tcx>> +{ + debug!("project(obligation={:?})", + obligation); + + let recursion_limit = selcx.tcx().sess.recursion_limit.get(); + if obligation.recursion_depth >= recursion_limit { + debug!("project: overflow!"); + report_overflow_error(selcx.infcx(), &obligation, true); + } + + let obligation_trait_ref = + selcx.infcx().resolve_type_vars_if_possible(&obligation.predicate.trait_ref); + + debug!("project: obligation_trait_ref={:?}", obligation_trait_ref); + + if obligation_trait_ref.references_error() { + return Ok(ProjectedTy::Progress(selcx.tcx().types.err, vec!())); + } + + let mut candidates = ProjectionTyCandidateSet { + vec: Vec::new(), + ambiguous: false, + }; + + assemble_candidates_from_param_env(selcx, + obligation, + &obligation_trait_ref, + &mut candidates); + + assemble_candidates_from_trait_def(selcx, + obligation, + &obligation_trait_ref, + &mut candidates); + + if let Err(e) = assemble_candidates_from_impls(selcx, + obligation, + &obligation_trait_ref, + &mut candidates) { + return Err(ProjectionTyError::TraitSelectionError(e)); + } + + debug!("{} candidates, ambiguous={}", + candidates.vec.len(), + candidates.ambiguous); + + // Inherent ambiguity that prevents us from even enumerating the + // candidates. + if candidates.ambiguous { + return Err(ProjectionTyError::TooManyCandidates); + } + + // Drop duplicates. + // + // Note: `candidates.vec` seems to be on the critical path of the + // compiler. Replacing it with an hash set was also tried, which would + // render the following dedup unnecessary. It led to cleaner code but + // prolonged compiling time of `librustc` from 5m30s to 6m in one test, or + // ~9% performance lost. + if candidates.vec.len() > 1 { + let mut i = 0; + while i < candidates.vec.len() { + let has_dup = (0..i).any(|j| candidates.vec[i] == candidates.vec[j]); + if has_dup { + candidates.vec.swap_remove(i); + } else { + i += 1; + } + } + } + + // Prefer where-clauses. As in select, if there are multiple + // candidates, we prefer where-clause candidates over impls. This + // may seem a bit surprising, since impls are the source of + // "truth" in some sense, but in fact some of the impls that SEEM + // applicable are not, because of nested obligations. Where + // clauses are the safer choice. See the comment on + // `select::SelectionCandidate` and #21974 for more details. + if candidates.vec.len() > 1 { + debug!("retaining param-env candidates only from {:?}", candidates.vec); + candidates.vec.retain(|c| match *c { + ProjectionTyCandidate::ParamEnv(..) => true, + ProjectionTyCandidate::Impl(..) | + ProjectionTyCandidate::Closure(..) | + ProjectionTyCandidate::TraitDef(..) | + ProjectionTyCandidate::FnPointer(..) => false, + }); + debug!("resulting candidate set: {:?}", candidates.vec); + if candidates.vec.len() != 1 { + return Err(ProjectionTyError::TooManyCandidates); + } + } + + assert!(candidates.vec.len() <= 1); + + let possible_candidate = candidates.vec.pop().and_then(|candidate| { + // In Any (i.e. trans) mode, all projections succeed; + // otherwise, we need to be sensitive to `default` and + // specialization. + if !selcx.projection_mode().is_any() { + if let ProjectionTyCandidate::Impl(ref impl_data) = candidate { + if let Some(node_item) = assoc_ty_def(selcx, + impl_data.impl_def_id, + obligation.predicate.item_name) { + if node_item.node.is_from_trait() { + if node_item.item.ty.is_some() { + // If the associated type has a default from the + // trait, that should be considered `default` and + // hence not projected. + // + // Note, however, that we allow a projection from + // the trait specifically in the case that the trait + // does *not* give a default. This is purely to + // avoid spurious errors: the situation can only + // arise when *no* impl in the specialization chain + // has provided a definition for the type. When we + // confirm the candidate, we'll turn the projection + // into a TyError, since the actual error will be + // reported in `check_impl_items_against_trait`. + return None; + } + } else if node_item.item.defaultness.is_default() { + return None; + } + } else { + // Normally this situation could only arise througha + // compiler bug, but at coherence-checking time we only look + // at the topmost impl (we don't even consider the trait + // itself) for the definition -- so we can fail to find a + // definition of the type even if it exists. + + // For now, we just unconditionally ICE, because otherwise, + // examples like the following will succeed: + // + // ``` + // trait Assoc { + // type Output; + // } + // + // impl Assoc for T { + // default type Output = bool; + // } + // + // impl Assoc for u8 {} + // impl Assoc for u16 {} + // + // trait Foo {} + // impl Foo for ::Output {} + // impl Foo for ::Output {} + // return None; + // } + // ``` + // + // The essential problem here is that the projection fails, + // leaving two unnormalized types, which appear not to unify + // -- so the overlap check succeeds, when it should fail. + selcx.tcx().sess.bug("Tried to project an inherited associated type during \ + coherence checking, which is currently not supported."); + } + } + } + Some(candidate) + }); + + match possible_candidate { + Some(candidate) => { + let (ty, obligations) = confirm_candidate(selcx, obligation, candidate); + Ok(ProjectedTy::Progress(ty, obligations)) + } + None => { + Ok(ProjectedTy::NoProgress(selcx.tcx().mk_projection( + obligation.predicate.trait_ref.clone(), + obligation.predicate.item_name))) + } + } +} + +/// The first thing we have to do is scan through the parameter +/// environment to see whether there are any projection predicates +/// there that can answer this question. +fn assemble_candidates_from_param_env<'cx,'tcx>( + selcx: &mut SelectionContext<'cx,'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + obligation_trait_ref: &ty::TraitRef<'tcx>, + candidate_set: &mut ProjectionTyCandidateSet<'tcx>) +{ + debug!("assemble_candidates_from_param_env(..)"); + let env_predicates = selcx.param_env().caller_bounds.iter().cloned(); + assemble_candidates_from_predicates(selcx, + obligation, + obligation_trait_ref, + candidate_set, + ProjectionTyCandidate::ParamEnv, + env_predicates); +} + +/// In the case of a nested projection like <::FooT as Bar>::BarT, we may find +/// that the definition of `Foo` has some clues: +/// +/// ``` +/// trait Foo { +/// type FooT : Bar +/// } +/// ``` +/// +/// Here, for example, we could conclude that the result is `i32`. +fn assemble_candidates_from_trait_def<'cx,'tcx>( + selcx: &mut SelectionContext<'cx,'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + obligation_trait_ref: &ty::TraitRef<'tcx>, + candidate_set: &mut ProjectionTyCandidateSet<'tcx>) +{ + debug!("assemble_candidates_from_trait_def(..)"); + + // Check whether the self-type is itself a projection. + let trait_ref = match obligation_trait_ref.self_ty().sty { + ty::TyProjection(ref data) => data.trait_ref.clone(), + ty::TyInfer(ty::TyVar(_)) => { + // If the self-type is an inference variable, then it MAY wind up + // being a projected type, so induce an ambiguity. + candidate_set.ambiguous = true; + return; + } + _ => { return; } + }; + + // If so, extract what we know from the trait and try to come up with a good answer. + let trait_predicates = selcx.tcx().lookup_predicates(trait_ref.def_id); + let bounds = trait_predicates.instantiate(selcx.tcx(), trait_ref.substs); + let bounds = elaborate_predicates(selcx.tcx(), bounds.predicates.into_vec()); + assemble_candidates_from_predicates(selcx, + obligation, + obligation_trait_ref, + candidate_set, + ProjectionTyCandidate::TraitDef, + bounds) +} + +fn assemble_candidates_from_predicates<'cx,'tcx,I>( + selcx: &mut SelectionContext<'cx,'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + obligation_trait_ref: &ty::TraitRef<'tcx>, + candidate_set: &mut ProjectionTyCandidateSet<'tcx>, + ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>, + env_predicates: I) + where I: Iterator> +{ + debug!("assemble_candidates_from_predicates(obligation={:?})", + obligation); + let infcx = selcx.infcx(); + for predicate in env_predicates { + debug!("assemble_candidates_from_predicates: predicate={:?}", + predicate); + match predicate { + ty::Predicate::Projection(ref data) => { + let same_name = data.item_name() == obligation.predicate.item_name; + + let is_match = same_name && infcx.probe(|_| { + let origin = TypeOrigin::Misc(obligation.cause.span); + let data_poly_trait_ref = + data.to_poly_trait_ref(); + let obligation_poly_trait_ref = + obligation_trait_ref.to_poly_trait_ref(); + infcx.sub_poly_trait_refs(false, + origin, + data_poly_trait_ref, + obligation_poly_trait_ref).is_ok() + }); + + debug!("assemble_candidates_from_predicates: candidate={:?} \ + is_match={} same_name={}", + data, is_match, same_name); + + if is_match { + candidate_set.vec.push(ctor(data.clone())); + } + } + _ => { } + } + } +} + +fn assemble_candidates_from_object_type<'cx,'tcx>( + selcx: &mut SelectionContext<'cx,'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + obligation_trait_ref: &ty::TraitRef<'tcx>, + candidate_set: &mut ProjectionTyCandidateSet<'tcx>) +{ + let self_ty = obligation_trait_ref.self_ty(); + let object_ty = selcx.infcx().shallow_resolve(self_ty); + debug!("assemble_candidates_from_object_type(object_ty={:?})", + object_ty); + let data = match object_ty.sty { + ty::TyTrait(ref data) => data, + _ => { + selcx.tcx().sess.span_bug( + obligation.cause.span, + &format!("assemble_candidates_from_object_type called with non-object: {:?}", + object_ty)); + } + }; + let projection_bounds = data.projection_bounds_with_self_ty(selcx.tcx(), object_ty); + let env_predicates = projection_bounds.iter() + .map(|p| p.to_predicate()) + .collect(); + let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates); + assemble_candidates_from_predicates(selcx, + obligation, + obligation_trait_ref, + candidate_set, + ProjectionTyCandidate::ParamEnv, + env_predicates) +} + +fn assemble_candidates_from_impls<'cx,'tcx>( + selcx: &mut SelectionContext<'cx,'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + obligation_trait_ref: &ty::TraitRef<'tcx>, + candidate_set: &mut ProjectionTyCandidateSet<'tcx>) + -> Result<(), SelectionError<'tcx>> +{ + // If we are resolving `>::Item == Type`, + // start out by selecting the predicate `T as TraitRef<...>`: + let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); + let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate()); + let vtable = match selcx.select(&trait_obligation) { + Ok(Some(vtable)) => vtable, + Ok(None) => { + candidate_set.ambiguous = true; + return Ok(()); + } + Err(e) => { + debug!("assemble_candidates_from_impls: selection error {:?}", + e); + return Err(e); + } + }; + + match vtable { + super::VtableImpl(data) => { + debug!("assemble_candidates_from_impls: impl candidate {:?}", + data); + + candidate_set.vec.push( + ProjectionTyCandidate::Impl(data)); + } + super::VtableObject(_) => { + assemble_candidates_from_object_type( + selcx, obligation, obligation_trait_ref, candidate_set); + } + super::VtableClosure(data) => { + candidate_set.vec.push( + ProjectionTyCandidate::Closure(data)); + } + super::VtableFnPointer(fn_type) => { + candidate_set.vec.push( + ProjectionTyCandidate::FnPointer(fn_type)); + } + super::VtableParam(..) => { + // This case tell us nothing about the value of an + // associated type. Consider: + // + // ``` + // trait SomeTrait { type Foo; } + // fn foo(...) { } + // ``` + // + // If the user writes `::Foo`, then the `T + // : SomeTrait` binding does not help us decide what the + // type `Foo` is (at least, not more specifically than + // what we already knew). + // + // But wait, you say! What about an example like this: + // + // ``` + // fn bar>(...) { ... } + // ``` + // + // Doesn't the `T : Sometrait` predicate help + // resolve `T::Foo`? And of course it does, but in fact + // that single predicate is desugared into two predicates + // in the compiler: a trait predicate (`T : SomeTrait`) and a + // projection. And the projection where clause is handled + // in `assemble_candidates_from_param_env`. + } + super::VtableDefaultImpl(..) | + super::VtableBuiltin(..) => { + // These traits have no associated types. + selcx.tcx().sess.span_bug( + obligation.cause.span, + &format!("Cannot project an associated type from `{:?}`", + vtable)); + } + } + + Ok(()) +} + +fn confirm_candidate<'cx,'tcx>( + selcx: &mut SelectionContext<'cx,'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + candidate: ProjectionTyCandidate<'tcx>) + -> (Ty<'tcx>, Vec>) +{ + debug!("confirm_candidate(candidate={:?}, obligation={:?})", + candidate, + obligation); + + match candidate { + ProjectionTyCandidate::ParamEnv(poly_projection) | + ProjectionTyCandidate::TraitDef(poly_projection) => { + confirm_param_env_candidate(selcx, obligation, poly_projection) + } + + ProjectionTyCandidate::Impl(impl_vtable) => { + confirm_impl_candidate(selcx, obligation, impl_vtable) + } + + ProjectionTyCandidate::Closure(closure_vtable) => { + confirm_closure_candidate(selcx, obligation, closure_vtable) + } + + ProjectionTyCandidate::FnPointer(fn_type) => { + confirm_fn_pointer_candidate(selcx, obligation, fn_type) + } + } +} + +fn confirm_fn_pointer_candidate<'cx,'tcx>( + selcx: &mut SelectionContext<'cx,'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + fn_type: Ty<'tcx>) + -> (Ty<'tcx>, Vec>) +{ + let fn_type = selcx.infcx().shallow_resolve(fn_type); + let sig = fn_type.fn_sig(); + confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes) +} + +fn confirm_closure_candidate<'cx,'tcx>( + selcx: &mut SelectionContext<'cx,'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + vtable: VtableClosureData<'tcx, PredicateObligation<'tcx>>) + -> (Ty<'tcx>, Vec>) +{ + let closure_typer = selcx.closure_typer(); + let closure_type = closure_typer.closure_type(vtable.closure_def_id, &vtable.substs); + let Normalized { + value: closure_type, + mut obligations + } = normalize_with_depth(selcx, + obligation.cause.clone(), + obligation.recursion_depth+1, + &closure_type); + let (ty, mut cc_obligations) = confirm_callable_candidate(selcx, + obligation, + &closure_type.sig, + util::TupleArgumentsFlag::No); + obligations.append(&mut cc_obligations); + (ty, obligations) +} + +fn confirm_callable_candidate<'cx,'tcx>( + selcx: &mut SelectionContext<'cx,'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + fn_sig: &ty::PolyFnSig<'tcx>, + flag: util::TupleArgumentsFlag) + -> (Ty<'tcx>, Vec>) +{ + let tcx = selcx.tcx(); + + debug!("confirm_callable_candidate({:?},{:?})", + obligation, + fn_sig); + + // the `Output` associated type is declared on `FnOnce` + let fn_once_def_id = tcx.lang_items.fn_once_trait().unwrap(); + + // Note: we unwrap the binder here but re-create it below (1) + let ty::Binder((trait_ref, ret_type)) = + util::closure_trait_ref_and_return_type(tcx, + fn_once_def_id, + obligation.predicate.trait_ref.self_ty(), + fn_sig, + flag); + + let predicate = ty::Binder(ty::ProjectionPredicate { // (1) recreate binder here + projection_ty: ty::ProjectionTy { + trait_ref: trait_ref, + item_name: token::intern(FN_OUTPUT_NAME), + }, + ty: ret_type + }); + + confirm_param_env_candidate(selcx, obligation, predicate) +} + +fn confirm_param_env_candidate<'cx,'tcx>( + selcx: &mut SelectionContext<'cx,'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + poly_projection: ty::PolyProjectionPredicate<'tcx>) + -> (Ty<'tcx>, Vec>) +{ + let infcx = selcx.infcx(); + + let projection = + infcx.replace_late_bound_regions_with_fresh_var( + obligation.cause.span, + infer::LateBoundRegionConversionTime::HigherRankedType, + &poly_projection).0; + + assert_eq!(projection.projection_ty.item_name, + obligation.predicate.item_name); + + let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); + match infcx.eq_trait_refs(false, + origin, + obligation.predicate.trait_ref.clone(), + projection.projection_ty.trait_ref.clone()) { + Ok(()) => { } + Err(e) => { + selcx.tcx().sess.span_bug( + obligation.cause.span, + &format!("Failed to unify `{:?}` and `{:?}` in projection: {}", + obligation, + projection, + e)); + } + } + + (projection.ty, vec!()) +} + +fn confirm_impl_candidate<'cx,'tcx>( + selcx: &mut SelectionContext<'cx,'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + impl_vtable: VtableImplData<'tcx, PredicateObligation<'tcx>>) + -> (Ty<'tcx>, Vec>) +{ + let VtableImplData { substs, nested, impl_def_id } = impl_vtable; + + let tcx = selcx.tcx(); + let trait_ref = obligation.predicate.trait_ref; + let assoc_ty = assoc_ty_def(selcx, impl_def_id, obligation.predicate.item_name); + + match assoc_ty { + Some(node_item) => { + let ty = node_item.item.ty.unwrap_or_else(|| { + // This means that the impl is missing a definition for the + // associated type. This error will be reported by the type + // checker method `check_impl_items_against_trait`, so here we + // just return TyError. + debug!("confirm_impl_candidate: no associated type {:?} for {:?}", + node_item.item.name, + obligation.predicate.trait_ref); + tcx.types.err + }); + let substs = translate_substs(selcx.infcx(), impl_def_id, substs, node_item.node); + (ty.subst(tcx, substs), nested) + } + None => { + tcx.sess.span_bug(obligation.cause.span, + &format!("No associated type for {:?}", trait_ref)); + } + } +} + +/// Locate the definition of an associated type in the specialization hierarchy, +/// starting from the given impl. +/// +/// Based on the "projection mode", this lookup may in fact only examine the +/// topmost impl. See the comments for `ProjectionMode` for more details. +fn assoc_ty_def<'cx, 'tcx>(selcx: &SelectionContext<'cx, 'tcx>, + impl_def_id: DefId, + assoc_ty_name: ast::Name) + -> Option>>> +{ + let trait_def_id = selcx.tcx().impl_trait_ref(impl_def_id).unwrap().def_id; + + if selcx.projection_mode().is_topmost() { + let impl_node = specialization_graph::Node::Impl(impl_def_id); + for item in impl_node.items(selcx.tcx()) { + if let ty::TypeTraitItem(assoc_ty) = item { + if assoc_ty.name == assoc_ty_name { + return Some(specialization_graph::NodeItem { + node: specialization_graph::Node::Impl(impl_def_id), + item: assoc_ty, + }); + } + } + } + None + } else { + selcx.tcx().lookup_trait_def(trait_def_id) + .ancestors(impl_def_id) + .type_defs(selcx.tcx(), assoc_ty_name) + .next() + } +} diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs new file mode 100644 index 00000000000..e2a48688d4b --- /dev/null +++ b/src/librustc/traits/select.rs @@ -0,0 +1,3049 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! See `README.md` for high-level documentation + +pub use self::MethodMatchResult::*; +pub use self::MethodMatchedData::*; +use self::SelectionCandidate::*; +use self::BuiltinBoundConditions::*; +use self::EvaluationResult::*; + +use super::coherence; +use super::DerivedObligationCause; +use super::project; +use super::project::{normalize_with_depth, Normalized}; +use super::{PredicateObligation, TraitObligation, ObligationCause}; +use super::report_overflow_error; +use super::{ObligationCauseCode, BuiltinDerivedObligation, ImplDerivedObligation}; +use super::{SelectionError, Unimplemented, OutputTypeParameterMismatch}; +use super::{ObjectCastObligation, Obligation}; +use super::ProjectionMode; +use super::TraitNotObjectSafe; +use super::Selection; +use super::SelectionResult; +use super::{VtableBuiltin, VtableImpl, VtableParam, VtableClosure, + VtableFnPointer, VtableObject, VtableDefaultImpl}; +use super::{VtableImplData, VtableObjectData, VtableBuiltinData, + VtableClosureData, VtableDefaultImplData}; +use super::object_safety; +use super::util; + +use middle::def_id::DefId; +use infer; +use infer::{InferCtxt, TypeFreshener, TypeOrigin}; +use ty::subst::{Subst, Substs, TypeSpace}; +use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; +use traits; +use ty::fast_reject; +use ty::relate::TypeRelation; + +use std::cell::RefCell; +use std::fmt; +use std::rc::Rc; +use syntax::abi::Abi; +use rustc_front::hir; +use util::common::ErrorReported; +use util::nodemap::FnvHashMap; + +pub struct SelectionContext<'cx, 'tcx:'cx> { + infcx: &'cx InferCtxt<'cx, 'tcx>, + + /// Freshener used specifically for skolemizing entries on the + /// obligation stack. This ensures that all entries on the stack + /// at one time will have the same set of skolemized entries, + /// which is important for checking for trait bounds that + /// recursively require themselves. + freshener: TypeFreshener<'cx, 'tcx>, + + /// If true, indicates that the evaluation should be conservative + /// and consider the possibility of types outside this crate. + /// This comes up primarily when resolving ambiguity. Imagine + /// there is some trait reference `$0 : Bar` where `$0` is an + /// inference variable. If `intercrate` is true, then we can never + /// say for sure that this reference is not implemented, even if + /// there are *no impls at all for `Bar`*, because `$0` could be + /// bound to some type that in a downstream crate that implements + /// `Bar`. This is the suitable mode for coherence. Elsewhere, + /// though, we set this to false, because we are only interested + /// in types that the user could actually have written --- in + /// other words, we consider `$0 : Bar` to be unimplemented if + /// there is no type that the user could *actually name* that + /// would satisfy it. This avoids crippling inference, basically. + intercrate: bool, +} + +// A stack that walks back up the stack frame. +struct TraitObligationStack<'prev, 'tcx: 'prev> { + obligation: &'prev TraitObligation<'tcx>, + + /// Trait ref from `obligation` but skolemized with the + /// selection-context's freshener. Used to check for recursion. + fresh_trait_ref: ty::PolyTraitRef<'tcx>, + + previous: TraitObligationStackList<'prev, 'tcx>, +} + +#[derive(Clone)] +pub struct SelectionCache<'tcx> { + hashmap: RefCell, + SelectionResult<'tcx, SelectionCandidate<'tcx>>>>, +} + +pub enum MethodMatchResult { + MethodMatched(MethodMatchedData), + MethodAmbiguous(/* list of impls that could apply */ Vec), + MethodDidNotMatch, +} + +#[derive(Copy, Clone, Debug)] +pub enum MethodMatchedData { + // In the case of a precise match, we don't really need to store + // how the match was found. So don't. + PreciseMethodMatch, + + // In the case of a coercion, we need to know the precise impl so + // that we can determine the type to which things were coerced. + CoerciveMethodMatch(/* impl we matched */ DefId) +} + +/// The selection process begins by considering all impls, where +/// clauses, and so forth that might resolve an obligation. Sometimes +/// we'll be able to say definitively that (e.g.) an impl does not +/// apply to the obligation: perhaps it is defined for `usize` but the +/// obligation is for `int`. In that case, we drop the impl out of the +/// list. But the other cases are considered *candidates*. +/// +/// For selection to succeed, there must be exactly one matching +/// candidate. If the obligation is fully known, this is guaranteed +/// by coherence. However, if the obligation contains type parameters +/// or variables, there may be multiple such impls. +/// +/// It is not a real problem if multiple matching impls exist because +/// of type variables - it just means the obligation isn't sufficiently +/// elaborated. In that case we report an ambiguity, and the caller can +/// try again after more type information has been gathered or report a +/// "type annotations required" error. +/// +/// However, with type parameters, this can be a real problem - type +/// parameters don't unify with regular types, but they *can* unify +/// with variables from blanket impls, and (unless we know its bounds +/// will always be satisfied) picking the blanket impl will be wrong +/// for at least *some* substitutions. To make this concrete, if we have +/// +/// trait AsDebug { type Out : fmt::Debug; fn debug(self) -> Self::Out; } +/// impl AsDebug for T { +/// type Out = T; +/// fn debug(self) -> fmt::Debug { self } +/// } +/// fn foo(t: T) { println!("{:?}", ::debug(t)); } +/// +/// we can't just use the impl to resolve the obligation +/// - a type from another crate (that doesn't implement fmt::Debug) could +/// implement AsDebug. +/// +/// Because where-clauses match the type exactly, multiple clauses can +/// only match if there are unresolved variables, and we can mostly just +/// report this ambiguity in that case. This is still a problem - we can't +/// *do anything* with ambiguities that involve only regions. This is issue +/// #21974. +/// +/// If a single where-clause matches and there are no inference +/// variables left, then it definitely matches and we can just select +/// it. +/// +/// In fact, we even select the where-clause when the obligation contains +/// inference variables. The can lead to inference making "leaps of logic", +/// for example in this situation: +/// +/// pub trait Foo { fn foo(&self) -> T; } +/// impl Foo<()> for T { fn foo(&self) { } } +/// impl Foo for bool { fn foo(&self) -> bool { *self } } +/// +/// pub fn foo(t: T) where T: Foo { +/// println!("{:?}", >::foo(&t)); +/// } +/// fn main() { foo(false); } +/// +/// Here the obligation > can be matched by both the blanket +/// impl and the where-clause. We select the where-clause and unify $0=bool, +/// so the program prints "false". However, if the where-clause is omitted, +/// the blanket impl is selected, we unify $0=(), and the program prints +/// "()". +/// +/// Exactly the same issues apply to projection and object candidates, except +/// that we can have both a projection candidate and a where-clause candidate +/// for the same obligation. In that case either would do (except that +/// different "leaps of logic" would occur if inference variables are +/// present), and we just pick the where-clause. This is, for example, +/// required for associated types to work in default impls, as the bounds +/// are visible both as projection bounds and as where-clauses from the +/// parameter environment. +#[derive(PartialEq,Eq,Debug,Clone)] +enum SelectionCandidate<'tcx> { + BuiltinCandidate(ty::BuiltinBound), + ParamCandidate(ty::PolyTraitRef<'tcx>), + ImplCandidate(DefId), + DefaultImplCandidate(DefId), + DefaultImplObjectCandidate(DefId), + + /// This is a trait matching with a projected type as `Self`, and + /// we found an applicable bound in the trait definition. + ProjectionCandidate, + + /// Implementation of a `Fn`-family trait by one of the + /// anonymous types generated for a `||` expression. + ClosureCandidate(/* closure */ DefId, &'tcx ty::ClosureSubsts<'tcx>), + + /// Implementation of a `Fn`-family trait by one of the anonymous + /// types generated for a fn pointer type (e.g., `fn(int)->int`) + FnPointerCandidate, + + ObjectCandidate, + + BuiltinObjectCandidate, + + BuiltinUnsizeCandidate, +} + +struct SelectionCandidateSet<'tcx> { + // a list of candidates that definitely apply to the current + // obligation (meaning: types unify). + vec: Vec>, + + // if this is true, then there were candidates that might or might + // not have applied, but we couldn't tell. This occurs when some + // of the input types are type variables, in which case there are + // various "builtin" rules that might or might not trigger. + ambiguous: bool, +} + +#[derive(PartialEq,Eq,Debug,Clone)] +struct EvaluatedCandidate<'tcx> { + candidate: SelectionCandidate<'tcx>, + evaluation: EvaluationResult, +} + +enum BuiltinBoundConditions<'tcx> { + If(ty::Binder>>), + ParameterBuiltin, + AmbiguousBuiltin +} + +#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] +/// The result of trait evaluation. The order is important +/// here as the evaluation of a list is the maximum of the +/// evaluations. +enum EvaluationResult { + /// Evaluation successful + EvaluatedToOk, + /// Evaluation failed because of recursion - treated as ambiguous + EvaluatedToUnknown, + /// Evaluation is known to be ambiguous + EvaluatedToAmbig, + /// Evaluation failed + EvaluatedToErr, +} + +#[derive(Clone)] +pub struct EvaluationCache<'tcx> { + hashmap: RefCell, EvaluationResult>> +} + +impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { + pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> { + SelectionContext { + infcx: infcx, + freshener: infcx.freshener(), + intercrate: false, + } + } + + pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> { + SelectionContext { + infcx: infcx, + freshener: infcx.freshener(), + intercrate: true, + } + } + + pub fn infcx(&self) -> &'cx InferCtxt<'cx, 'tcx> { + self.infcx + } + + pub fn tcx(&self) -> &'cx TyCtxt<'tcx> { + self.infcx.tcx + } + + pub fn param_env(&self) -> &'cx ty::ParameterEnvironment<'cx, 'tcx> { + self.infcx.param_env() + } + + pub fn closure_typer(&self) -> &'cx InferCtxt<'cx, 'tcx> { + self.infcx + } + + pub fn projection_mode(&self) -> ProjectionMode { + self.infcx.projection_mode() + } + + /////////////////////////////////////////////////////////////////////////// + // Selection + // + // The selection phase tries to identify *how* an obligation will + // be resolved. For example, it will identify which impl or + // parameter bound is to be used. The process can be inconclusive + // if the self type in the obligation is not fully inferred. Selection + // can result in an error in one of two ways: + // + // 1. If no applicable impl or parameter bound can be found. + // 2. If the output type parameters in the obligation do not match + // those specified by the impl/bound. For example, if the obligation + // is `Vec:Iterable`, but the impl specifies + // `impl Iterable for Vec`, than an error would result. + + /// Attempts to satisfy the obligation. If successful, this will affect the surrounding + /// type environment by performing unification. + pub fn select(&mut self, obligation: &TraitObligation<'tcx>) + -> SelectionResult<'tcx, Selection<'tcx>> { + debug!("select({:?})", obligation); + assert!(!obligation.predicate.has_escaping_regions()); + + let dep_node = obligation.predicate.dep_node(); + let _task = self.tcx().dep_graph.in_task(dep_node); + + let stack = self.push_stack(TraitObligationStackList::empty(), obligation); + match self.candidate_from_obligation(&stack)? { + None => { + self.consider_unification_despite_ambiguity(obligation); + Ok(None) + } + Some(candidate) => Ok(Some(self.confirm_candidate(obligation, candidate)?)), + } + } + + /// In the particular case of unboxed closure obligations, we can + /// sometimes do some amount of unification for the + /// argument/return types even though we can't yet fully match obligation. + /// The particular case we are interesting in is an obligation of the form: + /// + /// C : FnFoo + /// + /// where `C` is an unboxed closure type and `FnFoo` is one of the + /// `Fn` traits. Because we know that users cannot write impls for closure types + /// themselves, the only way that `C : FnFoo` can fail to match is under two + /// conditions: + /// + /// 1. The closure kind for `C` is not yet known, because inference isn't complete. + /// 2. The closure kind for `C` *is* known, but doesn't match what is needed. + /// For example, `C` may be a `FnOnce` closure, but a `Fn` closure is needed. + /// + /// In either case, we always know what argument types are + /// expected by `C`, no matter what kind of `Fn` trait it + /// eventually matches. So we can go ahead and unify the argument + /// types, even though the end result is ambiguous. + /// + /// Note that this is safe *even if* the trait would never be + /// matched (case 2 above). After all, in that case, an error will + /// result, so it kind of doesn't matter what we do --- unifying + /// the argument types can only be helpful to the user, because + /// once they patch up the kind of closure that is expected, the + /// argment types won't really change. + fn consider_unification_despite_ambiguity(&mut self, obligation: &TraitObligation<'tcx>) { + // Is this a `C : FnFoo(...)` trait reference for some trait binding `FnFoo`? + match self.tcx().lang_items.fn_trait_kind(obligation.predicate.0.def_id()) { + Some(_) => { } + None => { return; } + } + + // Is the self-type a closure type? We ignore bindings here + // because if it is a closure type, it must be a closure type from + // within this current fn, and hence none of the higher-ranked + // lifetimes can appear inside the self-type. + let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); + let (closure_def_id, substs) = match self_ty.sty { + ty::TyClosure(id, ref substs) => (id, substs), + _ => { return; } + }; + assert!(!substs.has_escaping_regions()); + + // It is OK to call the unnormalized variant here - this is only + // reached for TyClosure: Fn inputs where the closure kind is + // still unknown, which should only occur in typeck where the + // closure type is already normalized. + let closure_trait_ref = self.closure_trait_ref_unnormalized(obligation, + closure_def_id, + substs); + + match self.confirm_poly_trait_refs(obligation.cause.clone(), + obligation.predicate.to_poly_trait_ref(), + closure_trait_ref) { + Ok(()) => { } + Err(_) => { /* Silently ignore errors. */ } + } + } + + /////////////////////////////////////////////////////////////////////////// + // EVALUATION + // + // Tests whether an obligation can be selected or whether an impl + // can be applied to particular types. It skips the "confirmation" + // step and hence completely ignores output type parameters. + // + // The result is "true" if the obligation *may* hold and "false" if + // we can be sure it does not. + + /// Evaluates whether the obligation `obligation` can be satisfied (by any means). + pub fn evaluate_obligation(&mut self, + obligation: &PredicateObligation<'tcx>) + -> bool + { + debug!("evaluate_obligation({:?})", + obligation); + + self.infcx.probe(|_| { + self.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation) + .may_apply() + }) + } + + /// Evaluates whether the obligation `obligation` can be satisfied, + /// and returns `false` if not certain. However, this is not entirely + /// accurate if inference variables are involved. + pub fn evaluate_obligation_conservatively(&mut self, + obligation: &PredicateObligation<'tcx>) + -> bool + { + debug!("evaluate_obligation_conservatively({:?})", + obligation); + + self.infcx.probe(|_| { + self.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation) + == EvaluatedToOk + }) + } + + /// Evaluates the predicates in `predicates` recursively. Note that + /// this applies projections in the predicates, and therefore + /// is run within an inference probe. + fn evaluate_predicates_recursively<'a,'o,I>(&mut self, + stack: TraitObligationStackList<'o, 'tcx>, + predicates: I) + -> EvaluationResult + where I : Iterator>, 'tcx:'a + { + let mut result = EvaluatedToOk; + for obligation in predicates { + let eval = self.evaluate_predicate_recursively(stack, obligation); + debug!("evaluate_predicate_recursively({:?}) = {:?}", + obligation, eval); + match eval { + EvaluatedToErr => { return EvaluatedToErr; } + EvaluatedToAmbig => { result = EvaluatedToAmbig; } + EvaluatedToUnknown => { + if result < EvaluatedToUnknown { + result = EvaluatedToUnknown; + } + } + EvaluatedToOk => { } + } + } + result + } + + fn evaluate_predicate_recursively<'o>(&mut self, + previous_stack: TraitObligationStackList<'o, 'tcx>, + obligation: &PredicateObligation<'tcx>) + -> EvaluationResult + { + debug!("evaluate_predicate_recursively({:?})", + obligation); + + // Check the cache from the tcx of predicates that we know + // have been proven elsewhere. This cache only contains + // predicates that are global in scope and hence unaffected by + // the current environment. + if self.tcx().fulfilled_predicates.borrow().check_duplicate(&obligation.predicate) { + return EvaluatedToOk; + } + + match obligation.predicate { + ty::Predicate::Trait(ref t) => { + assert!(!t.has_escaping_regions()); + let obligation = obligation.with(t.clone()); + self.evaluate_obligation_recursively(previous_stack, &obligation) + } + + ty::Predicate::Equate(ref p) => { + // does this code ever run? + match self.infcx.equality_predicate(obligation.cause.span, p) { + Ok(()) => EvaluatedToOk, + Err(_) => EvaluatedToErr + } + } + + ty::Predicate::WellFormed(ty) => { + match ty::wf::obligations(self.infcx, obligation.cause.body_id, + ty, obligation.cause.span) { + Some(obligations) => + self.evaluate_predicates_recursively(previous_stack, obligations.iter()), + None => + EvaluatedToAmbig, + } + } + + ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => { + // we do not consider region relationships when + // evaluating trait matches + EvaluatedToOk + } + + ty::Predicate::ObjectSafe(trait_def_id) => { + if object_safety::is_object_safe(self.tcx(), trait_def_id) { + EvaluatedToOk + } else { + EvaluatedToErr + } + } + + ty::Predicate::Projection(ref data) => { + let project_obligation = obligation.with(data.clone()); + match project::poly_project_and_unify_type(self, &project_obligation) { + Ok(Some(subobligations)) => { + self.evaluate_predicates_recursively(previous_stack, + subobligations.iter()) + } + Ok(None) => { + EvaluatedToAmbig + } + Err(_) => { + EvaluatedToErr + } + } + } + } + } + + fn evaluate_obligation_recursively<'o>(&mut self, + previous_stack: TraitObligationStackList<'o, 'tcx>, + obligation: &TraitObligation<'tcx>) + -> EvaluationResult + { + debug!("evaluate_obligation_recursively({:?})", + obligation); + + let stack = self.push_stack(previous_stack, obligation); + let fresh_trait_ref = stack.fresh_trait_ref; + if let Some(result) = self.check_evaluation_cache(fresh_trait_ref) { + debug!("CACHE HIT: EVAL({:?})={:?}", + fresh_trait_ref, + result); + return result; + } + + let result = self.evaluate_stack(&stack); + + debug!("CACHE MISS: EVAL({:?})={:?}", + fresh_trait_ref, + result); + self.insert_evaluation_cache(fresh_trait_ref, result); + + result + } + + fn evaluate_stack<'o>(&mut self, + stack: &TraitObligationStack<'o, 'tcx>) + -> EvaluationResult + { + // In intercrate mode, whenever any of the types are unbound, + // there can always be an impl. Even if there are no impls in + // this crate, perhaps the type would be unified with + // something from another crate that does provide an impl. + // + // In intra mode, we must still be conservative. The reason is + // that we want to avoid cycles. Imagine an impl like: + // + // impl Eq for Vec + // + // and a trait reference like `$0 : Eq` where `$0` is an + // unbound variable. When we evaluate this trait-reference, we + // will unify `$0` with `Vec<$1>` (for some fresh variable + // `$1`), on the condition that `$1 : Eq`. We will then wind + // up with many candidates (since that are other `Eq` impls + // that apply) and try to winnow things down. This results in + // a recursive evaluation that `$1 : Eq` -- as you can + // imagine, this is just where we started. To avoid that, we + // check for unbound variables and return an ambiguous (hence possible) + // match if we've seen this trait before. + // + // This suffices to allow chains like `FnMut` implemented in + // terms of `Fn` etc, but we could probably make this more + // precise still. + let input_types = stack.fresh_trait_ref.0.input_types(); + let unbound_input_types = input_types.iter().any(|ty| ty.is_fresh()); + if unbound_input_types && self.intercrate { + debug!("evaluate_stack({:?}) --> unbound argument, intercrate --> ambiguous", + stack.fresh_trait_ref); + return EvaluatedToAmbig; + } + if unbound_input_types && + stack.iter().skip(1).any( + |prev| self.match_fresh_trait_refs(&stack.fresh_trait_ref, + &prev.fresh_trait_ref)) + { + debug!("evaluate_stack({:?}) --> unbound argument, recursive --> giving up", + stack.fresh_trait_ref); + return EvaluatedToUnknown; + } + + // If there is any previous entry on the stack that precisely + // matches this obligation, then we can assume that the + // obligation is satisfied for now (still all other conditions + // must be met of course). One obvious case this comes up is + // marker traits like `Send`. Think of a linked list: + // + // struct List { data: T, next: Option>> { + // + // `Box>` will be `Send` if `T` is `Send` and + // `Option>>` is `Send`, and in turn + // `Option>>` is `Send` if `Box>` is + // `Send`. + // + // Note that we do this comparison using the `fresh_trait_ref` + // fields. Because these have all been skolemized using + // `self.freshener`, we can be sure that (a) this will not + // affect the inferencer state and (b) that if we see two + // skolemized types with the same index, they refer to the + // same unbound type variable. + if + stack.iter() + .skip(1) // skip top-most frame + .any(|prev| stack.fresh_trait_ref == prev.fresh_trait_ref) + { + debug!("evaluate_stack({:?}) --> recursive", + stack.fresh_trait_ref); + return EvaluatedToOk; + } + + match self.candidate_from_obligation(stack) { + Ok(Some(c)) => self.evaluate_candidate(stack, &c), + Ok(None) => EvaluatedToAmbig, + Err(..) => EvaluatedToErr + } + } + + /// Further evaluate `candidate` to decide whether all type parameters match and whether nested + /// obligations are met. Returns true if `candidate` remains viable after this further + /// scrutiny. + fn evaluate_candidate<'o>(&mut self, + stack: &TraitObligationStack<'o, 'tcx>, + candidate: &SelectionCandidate<'tcx>) + -> EvaluationResult + { + debug!("evaluate_candidate: depth={} candidate={:?}", + stack.obligation.recursion_depth, candidate); + let result = self.infcx.probe(|_| { + let candidate = (*candidate).clone(); + match self.confirm_candidate(stack.obligation, candidate) { + Ok(selection) => { + self.evaluate_predicates_recursively( + stack.list(), + selection.nested_obligations().iter()) + } + Err(..) => EvaluatedToErr + } + }); + debug!("evaluate_candidate: depth={} result={:?}", + stack.obligation.recursion_depth, result); + result + } + + fn pick_evaluation_cache(&self) -> &EvaluationCache<'tcx> { + // see comment in `pick_candidate_cache` + if self.intercrate || + !self.param_env().caller_bounds.is_empty() + { + &self.param_env().evaluation_cache + } else + { + &self.tcx().evaluation_cache + } + } + + fn check_evaluation_cache(&self, trait_ref: ty::PolyTraitRef<'tcx>) + -> Option + { + let cache = self.pick_evaluation_cache(); + cache.hashmap.borrow().get(&trait_ref).cloned() + } + + fn insert_evaluation_cache(&mut self, + trait_ref: ty::PolyTraitRef<'tcx>, + result: EvaluationResult) + { + // Avoid caching results that depend on more than just the trait-ref: + // The stack can create EvaluatedToUnknown, and closure signatures + // being yet uninferred can create "spurious" EvaluatedToAmbig + // and EvaluatedToOk. + if result == EvaluatedToUnknown || + ((result == EvaluatedToAmbig || result == EvaluatedToOk) + && trait_ref.has_closure_types()) + { + return; + } + + let cache = self.pick_evaluation_cache(); + cache.hashmap.borrow_mut().insert(trait_ref, result); + } + + /////////////////////////////////////////////////////////////////////////// + // CANDIDATE ASSEMBLY + // + // The selection process begins by examining all in-scope impls, + // caller obligations, and so forth and assembling a list of + // candidates. See `README.md` and the `Candidate` type for more + // details. + + fn candidate_from_obligation<'o>(&mut self, + stack: &TraitObligationStack<'o, 'tcx>) + -> SelectionResult<'tcx, SelectionCandidate<'tcx>> + { + // Watch out for overflow. This intentionally bypasses (and does + // not update) the cache. + let recursion_limit = self.infcx.tcx.sess.recursion_limit.get(); + if stack.obligation.recursion_depth >= recursion_limit { + report_overflow_error(self.infcx(), &stack.obligation, true); + } + + // Check the cache. Note that we skolemize the trait-ref + // separately rather than using `stack.fresh_trait_ref` -- this + // is because we want the unbound variables to be replaced + // with fresh skolemized types starting from index 0. + let cache_fresh_trait_pred = + self.infcx.freshen(stack.obligation.predicate.clone()); + debug!("candidate_from_obligation(cache_fresh_trait_pred={:?}, obligation={:?})", + cache_fresh_trait_pred, + stack); + assert!(!stack.obligation.predicate.has_escaping_regions()); + + match self.check_candidate_cache(&cache_fresh_trait_pred) { + Some(c) => { + debug!("CACHE HIT: SELECT({:?})={:?}", + cache_fresh_trait_pred, + c); + return c; + } + None => { } + } + + // If no match, compute result and insert into cache. + let candidate = self.candidate_from_obligation_no_cache(stack); + + if self.should_update_candidate_cache(&cache_fresh_trait_pred, &candidate) { + debug!("CACHE MISS: SELECT({:?})={:?}", + cache_fresh_trait_pred, candidate); + self.insert_candidate_cache(cache_fresh_trait_pred, candidate.clone()); + } + + candidate + } + + // Treat negative impls as unimplemented + fn filter_negative_impls(&self, candidate: SelectionCandidate<'tcx>) + -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { + if let ImplCandidate(def_id) = candidate { + if self.tcx().trait_impl_polarity(def_id) == Some(hir::ImplPolarity::Negative) { + return Err(Unimplemented) + } + } + Ok(Some(candidate)) + } + + fn candidate_from_obligation_no_cache<'o>(&mut self, + stack: &TraitObligationStack<'o, 'tcx>) + -> SelectionResult<'tcx, SelectionCandidate<'tcx>> + { + if stack.obligation.predicate.references_error() { + // If we encounter a `TyError`, we generally prefer the + // most "optimistic" result in response -- that is, the + // one least likely to report downstream errors. But + // because this routine is shared by coherence and by + // trait selection, there isn't an obvious "right" choice + // here in that respect, so we opt to just return + // ambiguity and let the upstream clients sort it out. + return Ok(None); + } + + if !self.is_knowable(stack) { + debug!("coherence stage: not knowable"); + return Ok(None); + } + + let candidate_set = self.assemble_candidates(stack)?; + + if candidate_set.ambiguous { + debug!("candidate set contains ambig"); + return Ok(None); + } + + let mut candidates = candidate_set.vec; + + debug!("assembled {} candidates for {:?}: {:?}", + candidates.len(), + stack, + candidates); + + // At this point, we know that each of the entries in the + // candidate set is *individually* applicable. Now we have to + // figure out if they contain mutual incompatibilities. This + // frequently arises if we have an unconstrained input type -- + // for example, we are looking for $0:Eq where $0 is some + // unconstrained type variable. In that case, we'll get a + // candidate which assumes $0 == int, one that assumes $0 == + // usize, etc. This spells an ambiguity. + + // If there is more than one candidate, first winnow them down + // by considering extra conditions (nested obligations and so + // forth). We don't winnow if there is exactly one + // candidate. This is a relatively minor distinction but it + // can lead to better inference and error-reporting. An + // example would be if there was an impl: + // + // impl Vec { fn push_clone(...) { ... } } + // + // and we were to see some code `foo.push_clone()` where `boo` + // is a `Vec` and `Bar` does not implement `Clone`. If + // we were to winnow, we'd wind up with zero candidates. + // Instead, we select the right impl now but report `Bar does + // not implement Clone`. + if candidates.len() == 1 { + return self.filter_negative_impls(candidates.pop().unwrap()); + } + + // Winnow, but record the exact outcome of evaluation, which + // is needed for specialization. + let mut candidates: Vec<_> = candidates.into_iter().filter_map(|c| { + let eval = self.evaluate_candidate(stack, &c); + if eval.may_apply() { + Some(EvaluatedCandidate { + candidate: c, + evaluation: eval, + }) + } else { + None + } + }).collect(); + + // If there are STILL multiple candidate, we can further + // reduce the list by dropping duplicates -- including + // resolving specializations. + if candidates.len() > 1 { + let mut i = 0; + while i < candidates.len() { + let is_dup = + (0..candidates.len()) + .filter(|&j| i != j) + .any(|j| self.candidate_should_be_dropped_in_favor_of(&candidates[i], + &candidates[j])); + if is_dup { + debug!("Dropping candidate #{}/{}: {:?}", + i, candidates.len(), candidates[i]); + candidates.swap_remove(i); + } else { + debug!("Retaining candidate #{}/{}: {:?}", + i, candidates.len(), candidates[i]); + i += 1; + } + } + } + + // If there are *STILL* multiple candidates, give up and + // report ambiguity. + if candidates.len() > 1 { + debug!("multiple matches, ambig"); + return Ok(None); + } + + // If there are *NO* candidates, then there are no impls -- + // that we know of, anyway. Note that in the case where there + // are unbound type variables within the obligation, it might + // be the case that you could still satisfy the obligation + // from another crate by instantiating the type variables with + // a type from another crate that does have an impl. This case + // is checked for in `evaluate_stack` (and hence users + // who might care about this case, like coherence, should use + // that function). + if candidates.is_empty() { + return Err(Unimplemented); + } + + // Just one candidate left. + self.filter_negative_impls(candidates.pop().unwrap().candidate) + } + + fn is_knowable<'o>(&mut self, + stack: &TraitObligationStack<'o, 'tcx>) + -> bool + { + debug!("is_knowable(intercrate={})", self.intercrate); + + if !self.intercrate { + return true; + } + + let obligation = &stack.obligation; + let predicate = self.infcx().resolve_type_vars_if_possible(&obligation.predicate); + + // ok to skip binder because of the nature of the + // trait-ref-is-knowable check, which does not care about + // bound regions + let trait_ref = &predicate.skip_binder().trait_ref; + + coherence::trait_ref_is_knowable(self.tcx(), trait_ref) + } + + fn pick_candidate_cache(&self) -> &SelectionCache<'tcx> { + // If there are any where-clauses in scope, then we always use + // a cache local to this particular scope. Otherwise, we + // switch to a global cache. We used to try and draw + // finer-grained distinctions, but that led to a serious of + // annoying and weird bugs like #22019 and #18290. This simple + // rule seems to be pretty clearly safe and also still retains + // a very high hit rate (~95% when compiling rustc). + if !self.param_env().caller_bounds.is_empty() { + return &self.param_env().selection_cache; + } + + // Avoid using the master cache during coherence and just rely + // on the local cache. This effectively disables caching + // during coherence. It is really just a simplification to + // avoid us having to fear that coherence results "pollute" + // the master cache. Since coherence executes pretty quickly, + // it's not worth going to more trouble to increase the + // hit-rate I don't think. + if self.intercrate { + return &self.param_env().selection_cache; + } + + // Otherwise, we can use the global cache. + &self.tcx().selection_cache + } + + fn check_candidate_cache(&mut self, + cache_fresh_trait_pred: &ty::PolyTraitPredicate<'tcx>) + -> Option>> + { + let cache = self.pick_candidate_cache(); + let hashmap = cache.hashmap.borrow(); + hashmap.get(&cache_fresh_trait_pred.0.trait_ref).cloned() + } + + fn insert_candidate_cache(&mut self, + cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, + candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>) + { + let cache = self.pick_candidate_cache(); + let mut hashmap = cache.hashmap.borrow_mut(); + hashmap.insert(cache_fresh_trait_pred.0.trait_ref.clone(), candidate); + } + + fn should_update_candidate_cache(&mut self, + cache_fresh_trait_pred: &ty::PolyTraitPredicate<'tcx>, + candidate: &SelectionResult<'tcx, SelectionCandidate<'tcx>>) + -> bool + { + // In general, it's a good idea to cache results, even + // ambiguous ones, to save us some trouble later. But we have + // to be careful not to cache results that could be + // invalidated later by advances in inference. Normally, this + // is not an issue, because any inference variables whose + // types are not yet bound are "freshened" in the cache key, + // which means that if we later get the same request once that + // type variable IS bound, we'll have a different cache key. + // For example, if we have `Vec<_#0t> : Foo`, and `_#0t` is + // not yet known, we may cache the result as `None`. But if + // later `_#0t` is bound to `Bar`, then when we freshen we'll + // have `Vec : Foo` as the cache key. + // + // HOWEVER, it CAN happen that we get an ambiguity result in + // one particular case around closures where the cache key + // would not change. That is when the precise types of the + // upvars that a closure references have not yet been figured + // out (i.e., because it is not yet known if they are captured + // by ref, and if by ref, what kind of ref). In these cases, + // when matching a builtin bound, we will yield back an + // ambiguous result. But the *cache key* is just the closure type, + // it doesn't capture the state of the upvar computation. + // + // To avoid this trap, just don't cache ambiguous results if + // the self-type contains no inference byproducts (that really + // shouldn't happen in other circumstances anyway, given + // coherence). + + match *candidate { + Ok(Some(_)) | Err(_) => true, + Ok(None) => { + cache_fresh_trait_pred.0.trait_ref.substs.types.has_infer_types() + } + } + } + + fn assemble_candidates<'o>(&mut self, + stack: &TraitObligationStack<'o, 'tcx>) + -> Result, SelectionError<'tcx>> + { + let TraitObligationStack { obligation, .. } = *stack; + let ref obligation = Obligation { + cause: obligation.cause.clone(), + recursion_depth: obligation.recursion_depth, + predicate: self.infcx().resolve_type_vars_if_possible(&obligation.predicate) + }; + + if obligation.predicate.skip_binder().self_ty().is_ty_var() { + // FIXME(#20297): Self is a type variable (e.g. `_: AsRef`). + // + // This is somewhat problematic, as the current scheme can't really + // handle it turning to be a projection. This does end up as truly + // ambiguous in most cases anyway. + // + // Until this is fixed, take the fast path out - this also improves + // performance by preventing assemble_candidates_from_impls from + // matching every impl for this trait. + return Ok(SelectionCandidateSet { vec: vec![], ambiguous: true }); + } + + let mut candidates = SelectionCandidateSet { + vec: Vec::new(), + ambiguous: false + }; + + // Other bounds. Consider both in-scope bounds from fn decl + // and applicable impls. There is a certain set of precedence rules here. + + match self.tcx().lang_items.to_builtin_kind(obligation.predicate.def_id()) { + Some(ty::BoundCopy) => { + debug!("obligation self ty is {:?}", + obligation.predicate.0.self_ty()); + + // User-defined copy impls are permitted, but only for + // structs and enums. + self.assemble_candidates_from_impls(obligation, &mut candidates)?; + + // For other types, we'll use the builtin rules. + self.assemble_builtin_bound_candidates(ty::BoundCopy, + obligation, + &mut candidates)?; + } + Some(bound @ ty::BoundSized) => { + // Sized is never implementable by end-users, it is + // always automatically computed. + self.assemble_builtin_bound_candidates(bound, + obligation, + &mut candidates)?; + } + + None if self.tcx().lang_items.unsize_trait() == + Some(obligation.predicate.def_id()) => { + self.assemble_candidates_for_unsizing(obligation, &mut candidates); + } + + Some(ty::BoundSend) | + Some(ty::BoundSync) | + None => { + self.assemble_closure_candidates(obligation, &mut candidates)?; + self.assemble_fn_pointer_candidates(obligation, &mut candidates)?; + self.assemble_candidates_from_impls(obligation, &mut candidates)?; + self.assemble_candidates_from_object_ty(obligation, &mut candidates); + } + } + + self.assemble_candidates_from_projected_tys(obligation, &mut candidates); + self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?; + // Default implementations have lower priority, so we only + // consider triggering a default if there is no other impl that can apply. + if candidates.vec.is_empty() { + self.assemble_candidates_from_default_impls(obligation, &mut candidates)?; + } + debug!("candidate list size: {}", candidates.vec.len()); + Ok(candidates) + } + + fn assemble_candidates_from_projected_tys(&mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>) + { + debug!("assemble_candidates_for_projected_tys({:?})", obligation); + + // FIXME(#20297) -- just examining the self-type is very simplistic + + // before we go into the whole skolemization thing, just + // quickly check if the self-type is a projection at all. + let trait_def_id = match obligation.predicate.0.trait_ref.self_ty().sty { + ty::TyProjection(ref data) => data.trait_ref.def_id, + ty::TyInfer(ty::TyVar(_)) => { + self.tcx().sess.span_bug(obligation.cause.span, + "Self=_ should have been handled by assemble_candidates"); + } + _ => { return; } + }; + + debug!("assemble_candidates_for_projected_tys: trait_def_id={:?}", + trait_def_id); + + let result = self.infcx.probe(|snapshot| { + self.match_projection_obligation_against_bounds_from_trait(obligation, + snapshot) + }); + + if result { + candidates.vec.push(ProjectionCandidate); + } + } + + fn match_projection_obligation_against_bounds_from_trait( + &mut self, + obligation: &TraitObligation<'tcx>, + snapshot: &infer::CombinedSnapshot) + -> bool + { + let poly_trait_predicate = + self.infcx().resolve_type_vars_if_possible(&obligation.predicate); + let (skol_trait_predicate, skol_map) = + self.infcx().skolemize_late_bound_regions(&poly_trait_predicate, snapshot); + debug!("match_projection_obligation_against_bounds_from_trait: \ + skol_trait_predicate={:?} skol_map={:?}", + skol_trait_predicate, + skol_map); + + let projection_trait_ref = match skol_trait_predicate.trait_ref.self_ty().sty { + ty::TyProjection(ref data) => &data.trait_ref, + _ => { + self.tcx().sess.span_bug( + obligation.cause.span, + &format!("match_projection_obligation_against_bounds_from_trait() called \ + but self-ty not a projection: {:?}", + skol_trait_predicate.trait_ref.self_ty())); + } + }; + debug!("match_projection_obligation_against_bounds_from_trait: \ + projection_trait_ref={:?}", + projection_trait_ref); + + let trait_predicates = self.tcx().lookup_predicates(projection_trait_ref.def_id); + let bounds = trait_predicates.instantiate(self.tcx(), projection_trait_ref.substs); + debug!("match_projection_obligation_against_bounds_from_trait: \ + bounds={:?}", + bounds); + + let matching_bound = + util::elaborate_predicates(self.tcx(), bounds.predicates.into_vec()) + .filter_to_traits() + .find( + |bound| self.infcx.probe( + |_| self.match_projection(obligation, + bound.clone(), + skol_trait_predicate.trait_ref.clone(), + &skol_map, + snapshot))); + + debug!("match_projection_obligation_against_bounds_from_trait: \ + matching_bound={:?}", + matching_bound); + match matching_bound { + None => false, + Some(bound) => { + // Repeat the successful match, if any, this time outside of a probe. + let result = self.match_projection(obligation, + bound, + skol_trait_predicate.trait_ref.clone(), + &skol_map, + snapshot); + assert!(result); + true + } + } + } + + fn match_projection(&mut self, + obligation: &TraitObligation<'tcx>, + trait_bound: ty::PolyTraitRef<'tcx>, + skol_trait_ref: ty::TraitRef<'tcx>, + skol_map: &infer::SkolemizationMap, + snapshot: &infer::CombinedSnapshot) + -> bool + { + assert!(!skol_trait_ref.has_escaping_regions()); + let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); + match self.infcx.sub_poly_trait_refs(false, + origin, + trait_bound.clone(), + ty::Binder(skol_trait_ref.clone())) { + Ok(()) => { } + Err(_) => { return false; } + } + + self.infcx.leak_check(skol_map, snapshot).is_ok() + } + + /// Given an obligation like ``, search the obligations that the caller + /// supplied to find out whether it is listed among them. + /// + /// Never affects inference environment. + fn assemble_candidates_from_caller_bounds<'o>(&mut self, + stack: &TraitObligationStack<'o, 'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>) + -> Result<(),SelectionError<'tcx>> + { + debug!("assemble_candidates_from_caller_bounds({:?})", + stack.obligation); + + let all_bounds = + self.param_env().caller_bounds + .iter() + .filter_map(|o| o.to_opt_poly_trait_ref()); + + let matching_bounds = + all_bounds.filter( + |bound| self.evaluate_where_clause(stack, bound.clone()).may_apply()); + + let param_candidates = + matching_bounds.map(|bound| ParamCandidate(bound)); + + candidates.vec.extend(param_candidates); + + Ok(()) + } + + fn evaluate_where_clause<'o>(&mut self, + stack: &TraitObligationStack<'o, 'tcx>, + where_clause_trait_ref: ty::PolyTraitRef<'tcx>) + -> EvaluationResult + { + self.infcx().probe(move |_| { + match self.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { + Ok(obligations) => { + self.evaluate_predicates_recursively(stack.list(), obligations.iter()) + } + Err(()) => EvaluatedToErr + } + }) + } + + /// Check for the artificial impl that the compiler will create for an obligation like `X : + /// FnMut<..>` where `X` is a closure type. + /// + /// Note: the type parameters on a closure candidate are modeled as *output* type + /// parameters and hence do not affect whether this trait is a match or not. They will be + /// unified during the confirmation step. + fn assemble_closure_candidates(&mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>) + -> Result<(),SelectionError<'tcx>> + { + let kind = match self.tcx().lang_items.fn_trait_kind(obligation.predicate.0.def_id()) { + Some(k) => k, + None => { return Ok(()); } + }; + + // ok to skip binder because the substs on closure types never + // touch bound regions, they just capture the in-scope + // type/region parameters + let self_ty = *obligation.self_ty().skip_binder(); + let (closure_def_id, substs) = match self_ty.sty { + ty::TyClosure(id, ref substs) => (id, substs), + ty::TyInfer(ty::TyVar(_)) => { + debug!("assemble_unboxed_closure_candidates: ambiguous self-type"); + candidates.ambiguous = true; + return Ok(()); + } + _ => { return Ok(()); } + }; + + debug!("assemble_unboxed_candidates: self_ty={:?} kind={:?} obligation={:?}", + self_ty, + kind, + obligation); + + match self.infcx.closure_kind(closure_def_id) { + Some(closure_kind) => { + debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind); + if closure_kind.extends(kind) { + candidates.vec.push(ClosureCandidate(closure_def_id, substs)); + } + } + None => { + debug!("assemble_unboxed_candidates: closure_kind not yet known"); + candidates.ambiguous = true; + } + } + + Ok(()) + } + + /// Implement one of the `Fn()` family for a fn pointer. + fn assemble_fn_pointer_candidates(&mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>) + -> Result<(),SelectionError<'tcx>> + { + // We provide impl of all fn traits for fn pointers. + if self.tcx().lang_items.fn_trait_kind(obligation.predicate.def_id()).is_none() { + return Ok(()); + } + + // ok to skip binder because what we are inspecting doesn't involve bound regions + let self_ty = *obligation.self_ty().skip_binder(); + match self_ty.sty { + ty::TyInfer(ty::TyVar(_)) => { + debug!("assemble_fn_pointer_candidates: ambiguous self-type"); + candidates.ambiguous = true; // could wind up being a fn() type + } + + // provide an impl, but only for suitable `fn` pointers + ty::TyFnDef(_, _, &ty::BareFnTy { + unsafety: hir::Unsafety::Normal, + abi: Abi::Rust, + sig: ty::Binder(ty::FnSig { + inputs: _, + output: ty::FnConverging(_), + variadic: false + }) + }) | + ty::TyFnPtr(&ty::BareFnTy { + unsafety: hir::Unsafety::Normal, + abi: Abi::Rust, + sig: ty::Binder(ty::FnSig { + inputs: _, + output: ty::FnConverging(_), + variadic: false + }) + }) => { + candidates.vec.push(FnPointerCandidate); + } + + _ => { } + } + + Ok(()) + } + + /// Search for impls that might apply to `obligation`. + fn assemble_candidates_from_impls(&mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>) + -> Result<(), SelectionError<'tcx>> + { + debug!("assemble_candidates_from_impls(obligation={:?})", obligation); + + let def = self.tcx().lookup_trait_def(obligation.predicate.def_id()); + + def.for_each_relevant_impl( + self.tcx(), + obligation.predicate.0.trait_ref.self_ty(), + |impl_def_id| { + self.infcx.probe(|snapshot| { + if let Ok(_) = self.match_impl(impl_def_id, obligation, snapshot) { + candidates.vec.push(ImplCandidate(impl_def_id)); + } + }); + } + ); + + Ok(()) + } + + fn assemble_candidates_from_default_impls(&mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>) + -> Result<(), SelectionError<'tcx>> + { + // OK to skip binder here because the tests we do below do not involve bound regions + let self_ty = *obligation.self_ty().skip_binder(); + debug!("assemble_candidates_from_default_impls(self_ty={:?})", self_ty); + + let def_id = obligation.predicate.def_id(); + + if self.tcx().trait_has_default_impl(def_id) { + match self_ty.sty { + ty::TyTrait(..) => { + // For object types, we don't know what the closed + // over types are. For most traits, this means we + // conservatively say nothing; a candidate may be + // added by `assemble_candidates_from_object_ty`. + // However, for the kind of magic reflect trait, + // we consider it to be implemented even for + // object types, because it just lets you reflect + // onto the object type, not into the object's + // interior. + if self.tcx().has_attr(def_id, "rustc_reflect_like") { + candidates.vec.push(DefaultImplObjectCandidate(def_id)); + } + } + ty::TyParam(..) | + ty::TyProjection(..) => { + // In these cases, we don't know what the actual + // type is. Therefore, we cannot break it down + // into its constituent types. So we don't + // consider the `..` impl but instead just add no + // candidates: this means that typeck will only + // succeed if there is another reason to believe + // that this obligation holds. That could be a + // where-clause or, in the case of an object type, + // it could be that the object type lists the + // trait (e.g. `Foo+Send : Send`). See + // `compile-fail/typeck-default-trait-impl-send-param.rs` + // for an example of a test case that exercises + // this path. + } + ty::TyInfer(ty::TyVar(_)) => { + // the defaulted impl might apply, we don't know + candidates.ambiguous = true; + } + _ => { + candidates.vec.push(DefaultImplCandidate(def_id.clone())) + } + } + } + + Ok(()) + } + + /// Search for impls that might apply to `obligation`. + fn assemble_candidates_from_object_ty(&mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>) + { + debug!("assemble_candidates_from_object_ty(self_ty={:?})", + obligation.self_ty().skip_binder()); + + // Object-safety candidates are only applicable to object-safe + // traits. Including this check is useful because it helps + // inference in cases of traits like `BorrowFrom`, which are + // not object-safe, and which rely on being able to infer the + // self-type from one of the other inputs. Without this check, + // these cases wind up being considered ambiguous due to a + // (spurious) ambiguity introduced here. + let predicate_trait_ref = obligation.predicate.to_poly_trait_ref(); + if !object_safety::is_object_safe(self.tcx(), predicate_trait_ref.def_id()) { + return; + } + + self.infcx.commit_if_ok(|snapshot| { + let (self_ty, _) = + self.infcx().skolemize_late_bound_regions(&obligation.self_ty(), snapshot); + let poly_trait_ref = match self_ty.sty { + ty::TyTrait(ref data) => { + match self.tcx().lang_items.to_builtin_kind(obligation.predicate.def_id()) { + Some(bound @ ty::BoundSend) | Some(bound @ ty::BoundSync) => { + if data.bounds.builtin_bounds.contains(&bound) { + debug!("assemble_candidates_from_object_ty: matched builtin bound, \ + pushing candidate"); + candidates.vec.push(BuiltinObjectCandidate); + return Ok(()); + } + } + _ => {} + } + + data.principal_trait_ref_with_self_ty(self.tcx(), self_ty) + } + ty::TyInfer(ty::TyVar(_)) => { + debug!("assemble_candidates_from_object_ty: ambiguous"); + candidates.ambiguous = true; // could wind up being an object type + return Ok(()); + } + _ => { + return Ok(()); + } + }; + + debug!("assemble_candidates_from_object_ty: poly_trait_ref={:?}", + poly_trait_ref); + + // Count only those upcast versions that match the trait-ref + // we are looking for. Specifically, do not only check for the + // correct trait, but also the correct type parameters. + // For example, we may be trying to upcast `Foo` to `Bar`, + // but `Foo` is declared as `trait Foo : Bar`. + let upcast_trait_refs = + util::supertraits(self.tcx(), poly_trait_ref) + .filter(|upcast_trait_ref| { + self.infcx.probe(|_| { + let upcast_trait_ref = upcast_trait_ref.clone(); + self.match_poly_trait_ref(obligation, upcast_trait_ref).is_ok() + }) + }) + .count(); + + if upcast_trait_refs > 1 { + // can be upcast in many ways; need more type information + candidates.ambiguous = true; + } else if upcast_trait_refs == 1 { + candidates.vec.push(ObjectCandidate); + } + + Ok::<(),()>(()) + }).unwrap(); + } + + /// Search for unsizing that might apply to `obligation`. + fn assemble_candidates_for_unsizing(&mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>) { + // We currently never consider higher-ranked obligations e.g. + // `for<'a> &'a T: Unsize` to be implemented. This is not + // because they are a priori invalid, and we could potentially add support + // for them later, it's just that there isn't really a strong need for it. + // A `T: Unsize` obligation is always used as part of a `T: CoerceUnsize` + // impl, and those are generally applied to concrete types. + // + // That said, one might try to write a fn with a where clause like + // for<'a> Foo<'a, T>: Unsize> + // where the `'a` is kind of orthogonal to the relevant part of the `Unsize`. + // Still, you'd be more likely to write that where clause as + // T: Trait + // so it seems ok if we (conservatively) fail to accept that `Unsize` + // obligation above. Should be possible to extend this in the future. + let source = match self.tcx().no_late_bound_regions(&obligation.self_ty()) { + Some(t) => t, + None => { + // Don't add any candidates if there are bound regions. + return; + } + }; + let target = obligation.predicate.0.input_types()[0]; + + debug!("assemble_candidates_for_unsizing(source={:?}, target={:?})", + source, target); + + let may_apply = match (&source.sty, &target.sty) { + // Trait+Kx+'a -> Trait+Ky+'b (upcasts). + (&ty::TyTrait(ref data_a), &ty::TyTrait(ref data_b)) => { + // Upcasts permit two things: + // + // 1. Dropping builtin bounds, e.g. `Foo+Send` to `Foo` + // 2. Tightening the region bound, e.g. `Foo+'a` to `Foo+'b` if `'a : 'b` + // + // Note that neither of these changes requires any + // change at runtime. Eventually this will be + // generalized. + // + // We always upcast when we can because of reason + // #2 (region bounds). + data_a.principal.def_id() == data_a.principal.def_id() && + data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds) + } + + // T -> Trait. + (_, &ty::TyTrait(_)) => true, + + // Ambiguous handling is below T -> Trait, because inference + // variables can still implement Unsize and nested + // obligations will have the final say (likely deferred). + (&ty::TyInfer(ty::TyVar(_)), _) | + (_, &ty::TyInfer(ty::TyVar(_))) => { + debug!("assemble_candidates_for_unsizing: ambiguous"); + candidates.ambiguous = true; + false + } + + // [T; n] -> [T]. + (&ty::TyArray(_, _), &ty::TySlice(_)) => true, + + // Struct -> Struct. + (&ty::TyStruct(def_id_a, _), &ty::TyStruct(def_id_b, _)) => { + def_id_a == def_id_b + } + + _ => false + }; + + if may_apply { + candidates.vec.push(BuiltinUnsizeCandidate); + } + } + + /////////////////////////////////////////////////////////////////////////// + // WINNOW + // + // Winnowing is the process of attempting to resolve ambiguity by + // probing further. During the winnowing process, we unify all + // type variables (ignoring skolemization) and then we also + // attempt to evaluate recursive bounds to see if they are + // satisfied. + + /// Returns true if `candidate_i` should be dropped in favor of + /// `candidate_j`. Generally speaking we will drop duplicate + /// candidates and prefer where-clause candidates. + /// Returns true if `victim` should be dropped in favor of + /// `other`. Generally speaking we will drop duplicate + /// candidates and prefer where-clause candidates. + /// + /// See the comment for "SelectionCandidate" for more details. + fn candidate_should_be_dropped_in_favor_of<'o>( + &mut self, + victim: &EvaluatedCandidate<'tcx>, + other: &EvaluatedCandidate<'tcx>) + -> bool + { + if victim.candidate == other.candidate { + return true; + } + + match other.candidate { + ObjectCandidate | + ParamCandidate(_) | ProjectionCandidate => match victim.candidate { + DefaultImplCandidate(..) => { + self.tcx().sess.bug( + "default implementations shouldn't be recorded \ + when there are other valid candidates"); + } + ImplCandidate(..) | + ClosureCandidate(..) | + FnPointerCandidate | + BuiltinObjectCandidate | + BuiltinUnsizeCandidate | + DefaultImplObjectCandidate(..) | + BuiltinCandidate(..) => { + // We have a where-clause so don't go around looking + // for impls. + true + } + ObjectCandidate | + ProjectionCandidate => { + // Arbitrarily give param candidates priority + // over projection and object candidates. + true + }, + ParamCandidate(..) => false, + }, + ImplCandidate(other_def) => { + // See if we can toss out `victim` based on specialization. + // This requires us to know *for sure* that the `other` impl applies + // i.e. EvaluatedToOk: + if other.evaluation == EvaluatedToOk { + if let ImplCandidate(victim_def) = victim.candidate { + return traits::specializes(self.tcx(), other_def, victim_def); + } + } + + false + }, + _ => false + } + } + + /////////////////////////////////////////////////////////////////////////// + // BUILTIN BOUNDS + // + // These cover the traits that are built-in to the language + // itself. This includes `Copy` and `Sized` for sure. For the + // moment, it also includes `Send` / `Sync` and a few others, but + // those will hopefully change to library-defined traits in the + // future. + + fn assemble_builtin_bound_candidates<'o>(&mut self, + bound: ty::BuiltinBound, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>) + -> Result<(),SelectionError<'tcx>> + { + match self.builtin_bound(bound, obligation) { + Ok(If(..)) => { + debug!("builtin_bound: bound={:?}", + bound); + candidates.vec.push(BuiltinCandidate(bound)); + Ok(()) + } + Ok(ParameterBuiltin) => { Ok(()) } + Ok(AmbiguousBuiltin) => { + debug!("assemble_builtin_bound_candidates: ambiguous builtin"); + Ok(candidates.ambiguous = true) + } + Err(e) => { Err(e) } + } + } + + fn builtin_bound(&mut self, + bound: ty::BuiltinBound, + obligation: &TraitObligation<'tcx>) + -> Result,SelectionError<'tcx>> + { + // Note: these tests operate on types that may contain bound + // regions. To be proper, we ought to skolemize here, but we + // forego the skolemization and defer it until the + // confirmation step. + + let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.self_ty()); + return match self_ty.sty { + ty::TyInfer(ty::IntVar(_)) | + ty::TyInfer(ty::FloatVar(_)) | + ty::TyUint(_) | + ty::TyInt(_) | + ty::TyBool | + ty::TyFloat(_) | + ty::TyFnDef(..) | + ty::TyFnPtr(_) | + ty::TyChar => { + // safe for everything + ok_if(Vec::new()) + } + + ty::TyBox(_) => { // Box + match bound { + ty::BoundCopy => Err(Unimplemented), + + ty::BoundSized => ok_if(Vec::new()), + + ty::BoundSync | ty::BoundSend => { + self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()"); + } + } + } + + ty::TyRawPtr(..) => { // *const T, *mut T + match bound { + ty::BoundCopy | ty::BoundSized => ok_if(Vec::new()), + + ty::BoundSync | ty::BoundSend => { + self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()"); + } + } + } + + ty::TyTrait(ref data) => { + match bound { + ty::BoundSized => Err(Unimplemented), + ty::BoundCopy => { + if data.bounds.builtin_bounds.contains(&bound) { + ok_if(Vec::new()) + } else { + // Recursively check all supertraits to find out if any further + // bounds are required and thus we must fulfill. + let principal = + data.principal_trait_ref_with_self_ty(self.tcx(), + self.tcx().types.err); + let copy_def_id = obligation.predicate.def_id(); + for tr in util::supertraits(self.tcx(), principal) { + if tr.def_id() == copy_def_id { + return ok_if(Vec::new()) + } + } + + Err(Unimplemented) + } + } + ty::BoundSync | ty::BoundSend => { + self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()"); + } + } + } + + ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl }) => { + // &mut T or &T + match bound { + ty::BoundCopy => { + match mutbl { + // &mut T is affine and hence never `Copy` + hir::MutMutable => Err(Unimplemented), + + // &T is always copyable + hir::MutImmutable => ok_if(Vec::new()), + } + } + + ty::BoundSized => ok_if(Vec::new()), + + ty::BoundSync | ty::BoundSend => { + self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()"); + } + } + } + + ty::TyArray(element_ty, _) => { + // [T; n] + match bound { + ty::BoundCopy => ok_if(vec![element_ty]), + ty::BoundSized => ok_if(Vec::new()), + ty::BoundSync | ty::BoundSend => { + self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()"); + } + } + } + + ty::TyStr | ty::TySlice(_) => { + match bound { + ty::BoundSync | ty::BoundSend => { + self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()"); + } + + ty::BoundCopy | ty::BoundSized => Err(Unimplemented), + } + } + + // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet + ty::TyTuple(ref tys) => ok_if(tys.clone()), + + ty::TyClosure(_, ref substs) => { + // FIXME -- This case is tricky. In the case of by-ref + // closures particularly, we need the results of + // inference to decide how to reflect the type of each + // upvar (the upvar may have type `T`, but the runtime + // type could be `&mut`, `&`, or just `T`). For now, + // though, we'll do this unsoundly and assume that all + // captures are by value. Really what we ought to do + // is reserve judgement and then intertwine this + // analysis with closure inference. + + // Unboxed closures shouldn't be + // implicitly copyable + if bound == ty::BoundCopy { + return Ok(ParameterBuiltin); + } + + // Upvars are always local variables or references to + // local variables, and local variables cannot be + // unsized, so the closure struct as a whole must be + // Sized. + if bound == ty::BoundSized { + return ok_if(Vec::new()); + } + + ok_if(substs.upvar_tys.clone()) + } + + ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { + let types: Vec = def.all_fields().map(|f| { + f.ty(self.tcx(), substs) + }).collect(); + nominal(bound, types) + } + + ty::TyProjection(_) | ty::TyParam(_) => { + // Note: A type parameter is only considered to meet a + // particular bound if there is a where clause telling + // us that it does, and that case is handled by + // `assemble_candidates_from_caller_bounds()`. + Ok(ParameterBuiltin) + } + + ty::TyInfer(ty::TyVar(_)) => { + // Unbound type variable. Might or might not have + // applicable impls and so forth, depending on what + // those type variables wind up being bound to. + debug!("assemble_builtin_bound_candidates: ambiguous builtin"); + Ok(AmbiguousBuiltin) + } + + ty::TyError => ok_if(Vec::new()), + + ty::TyInfer(ty::FreshTy(_)) + | ty::TyInfer(ty::FreshIntTy(_)) + | ty::TyInfer(ty::FreshFloatTy(_)) => { + self.tcx().sess.bug( + &format!( + "asked to assemble builtin bounds of unexpected type: {:?}", + self_ty)); + } + }; + + fn ok_if<'tcx>(v: Vec>) + -> Result, SelectionError<'tcx>> { + Ok(If(ty::Binder(v))) + } + + fn nominal<'cx, 'tcx>(bound: ty::BuiltinBound, + types: Vec>) + -> Result, SelectionError<'tcx>> + { + // First check for markers and other nonsense. + match bound { + // Fallback to whatever user-defined impls exist in this case. + ty::BoundCopy => Ok(ParameterBuiltin), + + // Sized if all the component types are sized. + ty::BoundSized => ok_if(types), + + // Shouldn't be coming through here. + ty::BoundSend | ty::BoundSync => unreachable!(), + } + } + } + + /// For default impls, we need to break apart a type into its + /// "constituent types" -- meaning, the types that it contains. + /// + /// Here are some (simple) examples: + /// + /// ``` + /// (i32, u32) -> [i32, u32] + /// Foo where struct Foo { x: i32, y: u32 } -> [i32, u32] + /// Bar where struct Bar { x: T, y: u32 } -> [i32, u32] + /// Zed where enum Zed { A(T), B(u32) } -> [i32, u32] + /// ``` + fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec> { + match t.sty { + ty::TyUint(_) | + ty::TyInt(_) | + ty::TyBool | + ty::TyFloat(_) | + ty::TyFnDef(..) | + ty::TyFnPtr(_) | + ty::TyStr | + ty::TyError | + ty::TyInfer(ty::IntVar(_)) | + ty::TyInfer(ty::FloatVar(_)) | + ty::TyChar => { + Vec::new() + } + + ty::TyTrait(..) | + ty::TyParam(..) | + ty::TyProjection(..) | + ty::TyInfer(ty::TyVar(_)) | + ty::TyInfer(ty::FreshTy(_)) | + ty::TyInfer(ty::FreshIntTy(_)) | + ty::TyInfer(ty::FreshFloatTy(_)) => { + self.tcx().sess.bug( + &format!( + "asked to assemble constituent types of unexpected type: {:?}", + t)); + } + + ty::TyBox(referent_ty) => { // Box + vec![referent_ty] + } + + ty::TyRawPtr(ty::TypeAndMut { ty: element_ty, ..}) | + ty::TyRef(_, ty::TypeAndMut { ty: element_ty, ..}) => { + vec![element_ty] + }, + + ty::TyArray(element_ty, _) | ty::TySlice(element_ty) => { + vec![element_ty] + } + + ty::TyTuple(ref tys) => { + // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet + tys.clone() + } + + ty::TyClosure(_, ref substs) => { + // FIXME(#27086). We are invariant w/r/t our + // substs.func_substs, but we don't see them as + // constituent types; this seems RIGHT but also like + // something that a normal type couldn't simulate. Is + // this just a gap with the way that PhantomData and + // OIBIT interact? That is, there is no way to say + // "make me invariant with respect to this TYPE, but + // do not act as though I can reach it" + substs.upvar_tys.clone() + } + + // for `PhantomData`, we pass `T` + ty::TyStruct(def, substs) if def.is_phantom_data() => { + substs.types.get_slice(TypeSpace).to_vec() + } + + ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { + def.all_fields() + .map(|f| f.ty(self.tcx(), substs)) + .collect() + } + } + } + + fn collect_predicates_for_types(&mut self, + obligation: &TraitObligation<'tcx>, + trait_def_id: DefId, + types: ty::Binder>>) + -> Vec> + { + let derived_cause = match self.tcx().lang_items.to_builtin_kind(trait_def_id) { + Some(_) => { + self.derived_cause(obligation, BuiltinDerivedObligation) + }, + None => { + self.derived_cause(obligation, ImplDerivedObligation) + } + }; + + // Because the types were potentially derived from + // higher-ranked obligations they may reference late-bound + // regions. For example, `for<'a> Foo<&'a int> : Copy` would + // yield a type like `for<'a> &'a int`. In general, we + // maintain the invariant that we never manipulate bound + // regions, so we have to process these bound regions somehow. + // + // The strategy is to: + // + // 1. Instantiate those regions to skolemized regions (e.g., + // `for<'a> &'a int` becomes `&0 int`. + // 2. Produce something like `&'0 int : Copy` + // 3. Re-bind the regions back to `for<'a> &'a int : Copy` + + // Move the binder into the individual types + let bound_types: Vec>> = + types.skip_binder() + .iter() + .map(|&nested_ty| ty::Binder(nested_ty)) + .collect(); + + // For each type, produce a vector of resulting obligations + let obligations: Result>, _> = bound_types.iter().map(|nested_ty| { + self.infcx.commit_if_ok(|snapshot| { + let (skol_ty, skol_map) = + self.infcx().skolemize_late_bound_regions(nested_ty, snapshot); + let Normalized { value: normalized_ty, mut obligations } = + project::normalize_with_depth(self, + obligation.cause.clone(), + obligation.recursion_depth + 1, + &skol_ty); + let skol_obligation = + util::predicate_for_trait_def(self.tcx(), + derived_cause.clone(), + trait_def_id, + obligation.recursion_depth + 1, + normalized_ty, + vec![]); + obligations.push(skol_obligation); + Ok(self.infcx().plug_leaks(skol_map, snapshot, &obligations)) + }) + }).collect(); + + // Flatten those vectors (couldn't do it above due `collect`) + match obligations { + Ok(obligations) => obligations.into_iter().flat_map(|o| o).collect(), + Err(ErrorReported) => Vec::new(), + } + } + + /////////////////////////////////////////////////////////////////////////// + // CONFIRMATION + // + // Confirmation unifies the output type parameters of the trait + // with the values found in the obligation, possibly yielding a + // type error. See `README.md` for more details. + + fn confirm_candidate(&mut self, + obligation: &TraitObligation<'tcx>, + candidate: SelectionCandidate<'tcx>) + -> Result,SelectionError<'tcx>> + { + debug!("confirm_candidate({:?}, {:?})", + obligation, + candidate); + + match candidate { + BuiltinCandidate(builtin_bound) => { + Ok(VtableBuiltin( + self.confirm_builtin_candidate(obligation, builtin_bound)?)) + } + + ParamCandidate(param) => { + let obligations = self.confirm_param_candidate(obligation, param); + Ok(VtableParam(obligations)) + } + + DefaultImplCandidate(trait_def_id) => { + let data = self.confirm_default_impl_candidate(obligation, trait_def_id); + Ok(VtableDefaultImpl(data)) + } + + DefaultImplObjectCandidate(trait_def_id) => { + let data = self.confirm_default_impl_object_candidate(obligation, trait_def_id); + Ok(VtableDefaultImpl(data)) + } + + ImplCandidate(impl_def_id) => { + let vtable_impl = + self.confirm_impl_candidate(obligation, impl_def_id)?; + Ok(VtableImpl(vtable_impl)) + } + + ClosureCandidate(closure_def_id, substs) => { + let vtable_closure = + self.confirm_closure_candidate(obligation, closure_def_id, substs)?; + Ok(VtableClosure(vtable_closure)) + } + + BuiltinObjectCandidate => { + // This indicates something like `(Trait+Send) : + // Send`. In this case, we know that this holds + // because that's what the object type is telling us, + // and there's really no additional obligations to + // prove and no types in particular to unify etc. + Ok(VtableParam(Vec::new())) + } + + ObjectCandidate => { + let data = self.confirm_object_candidate(obligation); + Ok(VtableObject(data)) + } + + FnPointerCandidate => { + let fn_type = + self.confirm_fn_pointer_candidate(obligation)?; + Ok(VtableFnPointer(fn_type)) + } + + ProjectionCandidate => { + self.confirm_projection_candidate(obligation); + Ok(VtableParam(Vec::new())) + } + + BuiltinUnsizeCandidate => { + let data = self.confirm_builtin_unsize_candidate(obligation)?; + Ok(VtableBuiltin(data)) + } + } + } + + fn confirm_projection_candidate(&mut self, + obligation: &TraitObligation<'tcx>) + { + let _: Result<(),()> = + self.infcx.commit_if_ok(|snapshot| { + let result = + self.match_projection_obligation_against_bounds_from_trait(obligation, + snapshot); + assert!(result); + Ok(()) + }); + } + + fn confirm_param_candidate(&mut self, + obligation: &TraitObligation<'tcx>, + param: ty::PolyTraitRef<'tcx>) + -> Vec> + { + debug!("confirm_param_candidate({:?},{:?})", + obligation, + param); + + // During evaluation, we already checked that this + // where-clause trait-ref could be unified with the obligation + // trait-ref. Repeat that unification now without any + // transactional boundary; it should not fail. + match self.match_where_clause_trait_ref(obligation, param.clone()) { + Ok(obligations) => obligations, + Err(()) => { + self.tcx().sess.bug( + &format!("Where clause `{:?}` was applicable to `{:?}` but now is not", + param, + obligation)); + } + } + } + + fn confirm_builtin_candidate(&mut self, + obligation: &TraitObligation<'tcx>, + bound: ty::BuiltinBound) + -> Result>, + SelectionError<'tcx>> + { + debug!("confirm_builtin_candidate({:?})", + obligation); + + match self.builtin_bound(bound, obligation)? { + If(nested) => Ok(self.vtable_builtin_data(obligation, bound, nested)), + AmbiguousBuiltin | ParameterBuiltin => { + self.tcx().sess.span_bug( + obligation.cause.span, + &format!("builtin bound for {:?} was ambig", + obligation)); + } + } + } + + fn vtable_builtin_data(&mut self, + obligation: &TraitObligation<'tcx>, + bound: ty::BuiltinBound, + nested: ty::Binder>>) + -> VtableBuiltinData> + { + debug!("vtable_builtin_data(obligation={:?}, bound={:?}, nested={:?})", + obligation, bound, nested); + + let trait_def = match self.tcx().lang_items.from_builtin_kind(bound) { + Ok(def_id) => def_id, + Err(_) => { + self.tcx().sess.bug("builtin trait definition not found"); + } + }; + + let obligations = self.collect_predicates_for_types(obligation, trait_def, nested); + + debug!("vtable_builtin_data: obligations={:?}", + obligations); + + VtableBuiltinData { nested: obligations } + } + + /// This handles the case where a `impl Foo for ..` impl is being used. + /// The idea is that the impl applies to `X : Foo` if the following conditions are met: + /// + /// 1. For each constituent type `Y` in `X`, `Y : Foo` holds + /// 2. For each where-clause `C` declared on `Foo`, `[Self => X] C` holds. + fn confirm_default_impl_candidate(&mut self, + obligation: &TraitObligation<'tcx>, + trait_def_id: DefId) + -> VtableDefaultImplData> + { + debug!("confirm_default_impl_candidate({:?}, {:?})", + obligation, + trait_def_id); + + // binder is moved below + let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty()); + let types = self.constituent_types_for_ty(self_ty); + self.vtable_default_impl(obligation, trait_def_id, ty::Binder(types)) + } + + fn confirm_default_impl_object_candidate(&mut self, + obligation: &TraitObligation<'tcx>, + trait_def_id: DefId) + -> VtableDefaultImplData> + { + debug!("confirm_default_impl_object_candidate({:?}, {:?})", + obligation, + trait_def_id); + + assert!(self.tcx().has_attr(trait_def_id, "rustc_reflect_like")); + + // OK to skip binder, it is reintroduced below + let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty()); + match self_ty.sty { + ty::TyTrait(ref data) => { + // OK to skip the binder, it is reintroduced below + let input_types = data.principal.skip_binder().substs.types.get_slice(TypeSpace); + let assoc_types = data.bounds.projection_bounds + .iter() + .map(|pb| pb.skip_binder().ty); + let all_types: Vec<_> = input_types.iter().cloned() + .chain(assoc_types) + .collect(); + + // reintroduce the two binding levels we skipped, then flatten into one + let all_types = ty::Binder(ty::Binder(all_types)); + let all_types = self.tcx().flatten_late_bound_regions(&all_types); + + self.vtable_default_impl(obligation, trait_def_id, all_types) + } + _ => { + self.tcx().sess.bug( + &format!( + "asked to confirm default object implementation for non-object type: {:?}", + self_ty)); + } + } + } + + /// See `confirm_default_impl_candidate` + fn vtable_default_impl(&mut self, + obligation: &TraitObligation<'tcx>, + trait_def_id: DefId, + nested: ty::Binder>>) + -> VtableDefaultImplData> + { + debug!("vtable_default_impl_data: nested={:?}", nested); + + let mut obligations = self.collect_predicates_for_types(obligation, + trait_def_id, + nested); + + let trait_obligations: Result,()> = self.infcx.commit_if_ok(|snapshot| { + let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); + let (trait_ref, skol_map) = + self.infcx().skolemize_late_bound_regions(&poly_trait_ref, snapshot); + Ok(self.impl_or_trait_obligations(obligation.cause.clone(), + obligation.recursion_depth + 1, + trait_def_id, + &trait_ref.substs, + skol_map, + snapshot)) + }); + + // no Errors in that code above + obligations.append(&mut trait_obligations.unwrap()); + + debug!("vtable_default_impl_data: obligations={:?}", obligations); + + VtableDefaultImplData { + trait_def_id: trait_def_id, + nested: obligations + } + } + + fn confirm_impl_candidate(&mut self, + obligation: &TraitObligation<'tcx>, + impl_def_id: DefId) + -> Result>, + SelectionError<'tcx>> + { + debug!("confirm_impl_candidate({:?},{:?})", + obligation, + impl_def_id); + + // First, create the substitutions by matching the impl again, + // this time not in a probe. + self.infcx.commit_if_ok(|snapshot| { + let (substs, skol_map) = + self.rematch_impl(impl_def_id, obligation, + snapshot); + debug!("confirm_impl_candidate substs={:?}", substs); + Ok(self.vtable_impl(impl_def_id, substs, obligation.cause.clone(), + obligation.recursion_depth + 1, skol_map, snapshot)) + }) + } + + fn vtable_impl(&mut self, + impl_def_id: DefId, + mut substs: Normalized<'tcx, Substs<'tcx>>, + cause: ObligationCause<'tcx>, + recursion_depth: usize, + skol_map: infer::SkolemizationMap, + snapshot: &infer::CombinedSnapshot) + -> VtableImplData<'tcx, PredicateObligation<'tcx>> + { + debug!("vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={}, skol_map={:?})", + impl_def_id, + substs, + recursion_depth, + skol_map); + + let mut impl_obligations = + self.impl_or_trait_obligations(cause, + recursion_depth, + impl_def_id, + &substs.value, + skol_map, + snapshot); + + debug!("vtable_impl: impl_def_id={:?} impl_obligations={:?}", + impl_def_id, + impl_obligations); + + // Because of RFC447, the impl-trait-ref and obligations + // are sufficient to determine the impl substs, without + // relying on projections in the impl-trait-ref. + // + // e.g. `impl> Foo<::T> for V` + impl_obligations.append(&mut substs.obligations); + + VtableImplData { impl_def_id: impl_def_id, + substs: self.tcx().mk_substs(substs.value), + nested: impl_obligations } + } + + fn confirm_object_candidate(&mut self, + obligation: &TraitObligation<'tcx>) + -> VtableObjectData<'tcx> + { + debug!("confirm_object_candidate({:?})", + obligation); + + // FIXME skipping binder here seems wrong -- we should + // probably flatten the binder from the obligation and the + // binder from the object. Have to try to make a broken test + // case that results. -nmatsakis + let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); + let poly_trait_ref = match self_ty.sty { + ty::TyTrait(ref data) => { + data.principal_trait_ref_with_self_ty(self.tcx(), self_ty) + } + _ => { + self.tcx().sess.span_bug(obligation.cause.span, + "object candidate with non-object"); + } + }; + + let mut upcast_trait_ref = None; + let vtable_base; + + { + // We want to find the first supertrait in the list of + // supertraits that we can unify with, and do that + // unification. We know that there is exactly one in the list + // where we can unify because otherwise select would have + // reported an ambiguity. (When we do find a match, also + // record it for later.) + let nonmatching = + util::supertraits(self.tcx(), poly_trait_ref) + .take_while(|&t| { + match + self.infcx.commit_if_ok( + |_| self.match_poly_trait_ref(obligation, t)) + { + Ok(_) => { upcast_trait_ref = Some(t); false } + Err(_) => { true } + } + }); + + // Additionally, for each of the nonmatching predicates that + // we pass over, we sum up the set of number of vtable + // entries, so that we can compute the offset for the selected + // trait. + vtable_base = + nonmatching.map(|t| util::count_own_vtable_entries(self.tcx(), t)) + .sum(); + + } + + VtableObjectData { + upcast_trait_ref: upcast_trait_ref.unwrap(), + vtable_base: vtable_base, + } + } + + fn confirm_fn_pointer_candidate(&mut self, + obligation: &TraitObligation<'tcx>) + -> Result,SelectionError<'tcx>> + { + debug!("confirm_fn_pointer_candidate({:?})", + obligation); + + // ok to skip binder; it is reintroduced below + let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); + let sig = self_ty.fn_sig(); + let trait_ref = + util::closure_trait_ref_and_return_type(self.tcx(), + obligation.predicate.def_id(), + self_ty, + sig, + util::TupleArgumentsFlag::Yes) + .map_bound(|(trait_ref, _)| trait_ref); + + self.confirm_poly_trait_refs(obligation.cause.clone(), + obligation.predicate.to_poly_trait_ref(), + trait_ref)?; + Ok(self_ty) + } + + fn confirm_closure_candidate(&mut self, + obligation: &TraitObligation<'tcx>, + closure_def_id: DefId, + substs: &ty::ClosureSubsts<'tcx>) + -> Result>, + SelectionError<'tcx>> + { + debug!("confirm_closure_candidate({:?},{:?},{:?})", + obligation, + closure_def_id, + substs); + + let Normalized { + value: trait_ref, + obligations + } = self.closure_trait_ref(obligation, closure_def_id, substs); + + debug!("confirm_closure_candidate(closure_def_id={:?}, trait_ref={:?}, obligations={:?})", + closure_def_id, + trait_ref, + obligations); + + self.confirm_poly_trait_refs(obligation.cause.clone(), + obligation.predicate.to_poly_trait_ref(), + trait_ref)?; + + Ok(VtableClosureData { + closure_def_id: closure_def_id, + substs: substs.clone(), + nested: obligations + }) + } + + /// In the case of closure types and fn pointers, + /// we currently treat the input type parameters on the trait as + /// outputs. This means that when we have a match we have only + /// considered the self type, so we have to go back and make sure + /// to relate the argument types too. This is kind of wrong, but + /// since we control the full set of impls, also not that wrong, + /// and it DOES yield better error messages (since we don't report + /// errors as if there is no applicable impl, but rather report + /// errors are about mismatched argument types. + /// + /// Here is an example. Imagine we have a closure expression + /// and we desugared it so that the type of the expression is + /// `Closure`, and `Closure` expects an int as argument. Then it + /// is "as if" the compiler generated this impl: + /// + /// impl Fn(int) for Closure { ... } + /// + /// Now imagine our obligation is `Fn(usize) for Closure`. So far + /// we have matched the self-type `Closure`. At this point we'll + /// compare the `int` to `usize` and generate an error. + /// + /// Note that this checking occurs *after* the impl has selected, + /// because these output type parameters should not affect the + /// selection of the impl. Therefore, if there is a mismatch, we + /// report an error to the user. + fn confirm_poly_trait_refs(&mut self, + obligation_cause: ObligationCause, + obligation_trait_ref: ty::PolyTraitRef<'tcx>, + expected_trait_ref: ty::PolyTraitRef<'tcx>) + -> Result<(), SelectionError<'tcx>> + { + let origin = TypeOrigin::RelateOutputImplTypes(obligation_cause.span); + + let obligation_trait_ref = obligation_trait_ref.clone(); + match self.infcx.sub_poly_trait_refs(false, + origin, + expected_trait_ref.clone(), + obligation_trait_ref.clone()) { + Ok(()) => Ok(()), + Err(e) => Err(OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e)) + } + } + + fn confirm_builtin_unsize_candidate(&mut self, + obligation: &TraitObligation<'tcx>,) + -> Result>, + SelectionError<'tcx>> { + let tcx = self.tcx(); + + // assemble_candidates_for_unsizing should ensure there are no late bound + // regions here. See the comment there for more details. + let source = self.infcx.shallow_resolve( + tcx.no_late_bound_regions(&obligation.self_ty()).unwrap()); + let target = self.infcx.shallow_resolve(obligation.predicate.0.input_types()[0]); + + debug!("confirm_builtin_unsize_candidate(source={:?}, target={:?})", + source, target); + + let mut nested = vec![]; + match (&source.sty, &target.sty) { + // Trait+Kx+'a -> Trait+Ky+'b (upcasts). + (&ty::TyTrait(ref data_a), &ty::TyTrait(ref data_b)) => { + // See assemble_candidates_for_unsizing for more info. + let bounds = ty::ExistentialBounds { + region_bound: data_b.bounds.region_bound, + builtin_bounds: data_b.bounds.builtin_bounds, + projection_bounds: data_a.bounds.projection_bounds.clone(), + }; + + let new_trait = tcx.mk_trait(data_a.principal.clone(), bounds); + let origin = TypeOrigin::Misc(obligation.cause.span); + if self.infcx.sub_types(false, origin, new_trait, target).is_err() { + return Err(Unimplemented); + } + + // Register one obligation for 'a: 'b. + let cause = ObligationCause::new(obligation.cause.span, + obligation.cause.body_id, + ObjectCastObligation(target)); + let outlives = ty::OutlivesPredicate(data_a.bounds.region_bound, + data_b.bounds.region_bound); + nested.push(Obligation::with_depth(cause, + obligation.recursion_depth + 1, + ty::Binder(outlives).to_predicate())); + } + + // T -> Trait. + (_, &ty::TyTrait(ref data)) => { + let object_did = data.principal_def_id(); + if !object_safety::is_object_safe(tcx, object_did) { + return Err(TraitNotObjectSafe(object_did)); + } + + let cause = ObligationCause::new(obligation.cause.span, + obligation.cause.body_id, + ObjectCastObligation(target)); + let mut push = |predicate| { + nested.push(Obligation::with_depth(cause.clone(), + obligation.recursion_depth + 1, + predicate)); + }; + + // Create the obligation for casting from T to Trait. + push(data.principal_trait_ref_with_self_ty(tcx, source).to_predicate()); + + // We can only make objects from sized types. + let mut builtin_bounds = data.bounds.builtin_bounds; + builtin_bounds.insert(ty::BoundSized); + + // Create additional obligations for all the various builtin + // bounds attached to the object cast. (In other words, if the + // object type is Foo+Send, this would create an obligation + // for the Send check.) + for bound in &builtin_bounds { + if let Ok(tr) = util::trait_ref_for_builtin_bound(tcx, bound, source) { + push(tr.to_predicate()); + } else { + return Err(Unimplemented); + } + } + + // Create obligations for the projection predicates. + for bound in data.projection_bounds_with_self_ty(tcx, source) { + push(bound.to_predicate()); + } + + // If the type is `Foo+'a`, ensures that the type + // being cast to `Foo+'a` outlives `'a`: + let outlives = ty::OutlivesPredicate(source, + data.bounds.region_bound); + push(ty::Binder(outlives).to_predicate()); + } + + // [T; n] -> [T]. + (&ty::TyArray(a, _), &ty::TySlice(b)) => { + let origin = TypeOrigin::Misc(obligation.cause.span); + if self.infcx.sub_types(false, origin, a, b).is_err() { + return Err(Unimplemented); + } + } + + // Struct -> Struct. + (&ty::TyStruct(def, substs_a), &ty::TyStruct(_, substs_b)) => { + let fields = def + .all_fields() + .map(|f| f.unsubst_ty()) + .collect::>(); + + // The last field of the structure has to exist and contain type parameters. + let field = if let Some(&field) = fields.last() { + field + } else { + return Err(Unimplemented); + }; + let mut ty_params = vec![]; + for ty in field.walk() { + if let ty::TyParam(p) = ty.sty { + assert!(p.space == TypeSpace); + let idx = p.idx as usize; + if !ty_params.contains(&idx) { + ty_params.push(idx); + } + } + } + if ty_params.is_empty() { + return Err(Unimplemented); + } + + // Replace type parameters used in unsizing with + // TyError and ensure they do not affect any other fields. + // This could be checked after type collection for any struct + // with a potentially unsized trailing field. + let mut new_substs = substs_a.clone(); + for &i in &ty_params { + new_substs.types.get_mut_slice(TypeSpace)[i] = tcx.types.err; + } + for &ty in fields.split_last().unwrap().1 { + if ty.subst(tcx, &new_substs).references_error() { + return Err(Unimplemented); + } + } + + // Extract Field and Field from Struct and Struct. + let inner_source = field.subst(tcx, substs_a); + let inner_target = field.subst(tcx, substs_b); + + // Check that the source structure with the target's + // type parameters is a subtype of the target. + for &i in &ty_params { + let param_b = *substs_b.types.get(TypeSpace, i); + new_substs.types.get_mut_slice(TypeSpace)[i] = param_b; + } + let new_struct = tcx.mk_struct(def, tcx.mk_substs(new_substs)); + let origin = TypeOrigin::Misc(obligation.cause.span); + if self.infcx.sub_types(false, origin, new_struct, target).is_err() { + return Err(Unimplemented); + } + + // Construct the nested Field: Unsize> predicate. + nested.push(util::predicate_for_trait_def(tcx, + obligation.cause.clone(), + obligation.predicate.def_id(), + obligation.recursion_depth + 1, + inner_source, + vec![inner_target])); + } + + _ => unreachable!() + }; + + Ok(VtableBuiltinData { nested: nested }) + } + + /////////////////////////////////////////////////////////////////////////// + // Matching + // + // Matching is a common path used for both evaluation and + // confirmation. It basically unifies types that appear in impls + // and traits. This does affect the surrounding environment; + // therefore, when used during evaluation, match routines must be + // run inside of a `probe()` so that their side-effects are + // contained. + + fn rematch_impl(&mut self, + impl_def_id: DefId, + obligation: &TraitObligation<'tcx>, + snapshot: &infer::CombinedSnapshot) + -> (Normalized<'tcx, Substs<'tcx>>, infer::SkolemizationMap) + { + match self.match_impl(impl_def_id, obligation, snapshot) { + Ok((substs, skol_map)) => (substs, skol_map), + Err(()) => { + self.tcx().sess.bug( + &format!("Impl {:?} was matchable against {:?} but now is not", + impl_def_id, + obligation)); + } + } + } + + fn match_impl(&mut self, + impl_def_id: DefId, + obligation: &TraitObligation<'tcx>, + snapshot: &infer::CombinedSnapshot) + -> Result<(Normalized<'tcx, Substs<'tcx>>, + infer::SkolemizationMap), ()> + { + let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); + + // Before we create the substitutions and everything, first + // consider a "quick reject". This avoids creating more types + // and so forth that we need to. + if self.fast_reject_trait_refs(obligation, &impl_trait_ref) { + return Err(()); + } + + let (skol_obligation, skol_map) = self.infcx().skolemize_late_bound_regions( + &obligation.predicate, + snapshot); + let skol_obligation_trait_ref = skol_obligation.trait_ref; + + let impl_substs = util::fresh_type_vars_for_impl(self.infcx, + obligation.cause.span, + impl_def_id); + + let impl_trait_ref = impl_trait_ref.subst(self.tcx(), + &impl_substs); + + let impl_trait_ref = + project::normalize_with_depth(self, + obligation.cause.clone(), + obligation.recursion_depth + 1, + &impl_trait_ref); + + debug!("match_impl(impl_def_id={:?}, obligation={:?}, \ + impl_trait_ref={:?}, skol_obligation_trait_ref={:?})", + impl_def_id, + obligation, + impl_trait_ref, + skol_obligation_trait_ref); + + let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); + if let Err(e) = self.infcx.eq_trait_refs(false, + origin, + impl_trait_ref.value.clone(), + skol_obligation_trait_ref) { + debug!("match_impl: failed eq_trait_refs due to `{}`", e); + return Err(()); + } + + if let Err(e) = self.infcx.leak_check(&skol_map, snapshot) { + debug!("match_impl: failed leak check due to `{}`", e); + return Err(()); + } + + debug!("match_impl: success impl_substs={:?}", impl_substs); + Ok((Normalized { + value: impl_substs, + obligations: impl_trait_ref.obligations + }, skol_map)) + } + + fn fast_reject_trait_refs(&mut self, + obligation: &TraitObligation, + impl_trait_ref: &ty::TraitRef) + -> bool + { + // We can avoid creating type variables and doing the full + // substitution if we find that any of the input types, when + // simplified, do not match. + + obligation.predicate.0.input_types().iter() + .zip(impl_trait_ref.input_types()) + .any(|(&obligation_ty, &impl_ty)| { + let simplified_obligation_ty = + fast_reject::simplify_type(self.tcx(), obligation_ty, true); + let simplified_impl_ty = + fast_reject::simplify_type(self.tcx(), impl_ty, false); + + simplified_obligation_ty.is_some() && + simplified_impl_ty.is_some() && + simplified_obligation_ty != simplified_impl_ty + }) + } + + /// Normalize `where_clause_trait_ref` and try to match it against + /// `obligation`. If successful, return any predicates that + /// result from the normalization. Normalization is necessary + /// because where-clauses are stored in the parameter environment + /// unnormalized. + fn match_where_clause_trait_ref(&mut self, + obligation: &TraitObligation<'tcx>, + where_clause_trait_ref: ty::PolyTraitRef<'tcx>) + -> Result>,()> + { + self.match_poly_trait_ref(obligation, where_clause_trait_ref)?; + Ok(Vec::new()) + } + + /// Returns `Ok` if `poly_trait_ref` being true implies that the + /// obligation is satisfied. + fn match_poly_trait_ref(&self, + obligation: &TraitObligation<'tcx>, + poly_trait_ref: ty::PolyTraitRef<'tcx>) + -> Result<(),()> + { + debug!("match_poly_trait_ref: obligation={:?} poly_trait_ref={:?}", + obligation, + poly_trait_ref); + + let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); + match self.infcx.sub_poly_trait_refs(false, + origin, + poly_trait_ref, + obligation.predicate.to_poly_trait_ref()) { + Ok(()) => Ok(()), + Err(_) => Err(()), + } + } + + /////////////////////////////////////////////////////////////////////////// + // Miscellany + + fn match_fresh_trait_refs(&self, + previous: &ty::PolyTraitRef<'tcx>, + current: &ty::PolyTraitRef<'tcx>) + -> bool + { + let mut matcher = ty::_match::Match::new(self.tcx()); + matcher.relate(previous, current).is_ok() + } + + fn push_stack<'o,'s:'o>(&mut self, + previous_stack: TraitObligationStackList<'s, 'tcx>, + obligation: &'o TraitObligation<'tcx>) + -> TraitObligationStack<'o, 'tcx> + { + let fresh_trait_ref = + obligation.predicate.to_poly_trait_ref().fold_with(&mut self.freshener); + + TraitObligationStack { + obligation: obligation, + fresh_trait_ref: fresh_trait_ref, + previous: previous_stack, + } + } + + fn closure_trait_ref_unnormalized(&mut self, + obligation: &TraitObligation<'tcx>, + closure_def_id: DefId, + substs: &ty::ClosureSubsts<'tcx>) + -> ty::PolyTraitRef<'tcx> + { + let closure_type = self.infcx.closure_type(closure_def_id, substs); + let ty::Binder((trait_ref, _)) = + util::closure_trait_ref_and_return_type(self.tcx(), + obligation.predicate.def_id(), + obligation.predicate.0.self_ty(), // (1) + &closure_type.sig, + util::TupleArgumentsFlag::No); + // (1) Feels icky to skip the binder here, but OTOH we know + // that the self-type is an unboxed closure type and hence is + // in fact unparameterized (or at least does not reference any + // regions bound in the obligation). Still probably some + // refactoring could make this nicer. + + ty::Binder(trait_ref) + } + + fn closure_trait_ref(&mut self, + obligation: &TraitObligation<'tcx>, + closure_def_id: DefId, + substs: &ty::ClosureSubsts<'tcx>) + -> Normalized<'tcx, ty::PolyTraitRef<'tcx>> + { + let trait_ref = self.closure_trait_ref_unnormalized( + obligation, closure_def_id, substs); + + // A closure signature can contain associated types which + // must be normalized. + normalize_with_depth(self, + obligation.cause.clone(), + obligation.recursion_depth+1, + &trait_ref) + } + + /// Returns the obligations that are implied by instantiating an + /// impl or trait. The obligations are substituted and fully + /// normalized. This is used when confirming an impl or default + /// impl. + fn impl_or_trait_obligations(&mut self, + cause: ObligationCause<'tcx>, + recursion_depth: usize, + def_id: DefId, // of impl or trait + substs: &Substs<'tcx>, // for impl or trait + skol_map: infer::SkolemizationMap, + snapshot: &infer::CombinedSnapshot) + -> Vec> + { + debug!("impl_or_trait_obligations(def_id={:?})", def_id); + let tcx = self.tcx(); + + // To allow for one-pass evaluation of the nested obligation, + // each predicate must be preceded by the obligations required + // to normalize it. + // for example, if we have: + // impl> Foo for V where U::Item: Copy + // the impl will have the following predicates: + // ::Item = U, + // U: Iterator, U: Sized, + // V: Iterator, V: Sized, + // ::Item: Copy + // When we substitute, say, `V => IntoIter, U => $0`, the last + // obligation will normalize to `<$0 as Iterator>::Item = $1` and + // `$1: Copy`, so we must ensure the obligations are emitted in + // that order. + let predicates = tcx + .lookup_predicates(def_id) + .predicates.iter() + .flat_map(|predicate| { + let predicate = + normalize_with_depth(self, cause.clone(), recursion_depth, + &predicate.subst(tcx, substs)); + predicate.obligations.into_iter().chain( + Some(Obligation { + cause: cause.clone(), + recursion_depth: recursion_depth, + predicate: predicate.value + })) + }).collect(); + self.infcx().plug_leaks(skol_map, snapshot, &predicates) + } + + #[allow(unused_comparisons)] + fn derived_cause(&self, + obligation: &TraitObligation<'tcx>, + variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>) + -> ObligationCause<'tcx> + { + /*! + * Creates a cause for obligations that are derived from + * `obligation` by a recursive search (e.g., for a builtin + * bound, or eventually a `impl Foo for ..`). If `obligation` + * is itself a derived obligation, this is just a clone, but + * otherwise we create a "derived obligation" cause so as to + * keep track of the original root obligation for error + * reporting. + */ + + // NOTE(flaper87): As of now, it keeps track of the whole error + // chain. Ideally, we should have a way to configure this either + // by using -Z verbose or just a CLI argument. + if obligation.recursion_depth >= 0 { + let derived_cause = DerivedObligationCause { + parent_trait_ref: obligation.predicate.to_poly_trait_ref(), + parent_code: Rc::new(obligation.cause.code.clone()) + }; + let derived_code = variant(derived_cause); + ObligationCause::new(obligation.cause.span, obligation.cause.body_id, derived_code) + } else { + obligation.cause.clone() + } + } +} + +impl<'tcx> SelectionCache<'tcx> { + pub fn new() -> SelectionCache<'tcx> { + SelectionCache { + hashmap: RefCell::new(FnvHashMap()) + } + } +} + +impl<'tcx> EvaluationCache<'tcx> { + pub fn new() -> EvaluationCache<'tcx> { + EvaluationCache { + hashmap: RefCell::new(FnvHashMap()) + } + } +} + +impl<'o,'tcx> TraitObligationStack<'o,'tcx> { + fn list(&'o self) -> TraitObligationStackList<'o,'tcx> { + TraitObligationStackList::with(self) + } + + fn iter(&'o self) -> TraitObligationStackList<'o,'tcx> { + self.list() + } +} + +#[derive(Copy, Clone)] +struct TraitObligationStackList<'o,'tcx:'o> { + head: Option<&'o TraitObligationStack<'o,'tcx>> +} + +impl<'o,'tcx> TraitObligationStackList<'o,'tcx> { + fn empty() -> TraitObligationStackList<'o,'tcx> { + TraitObligationStackList { head: None } + } + + fn with(r: &'o TraitObligationStack<'o,'tcx>) -> TraitObligationStackList<'o,'tcx> { + TraitObligationStackList { head: Some(r) } + } +} + +impl<'o,'tcx> Iterator for TraitObligationStackList<'o,'tcx>{ + type Item = &'o TraitObligationStack<'o,'tcx>; + + fn next(&mut self) -> Option<&'o TraitObligationStack<'o,'tcx>> { + match self.head { + Some(o) => { + *self = o.previous; + Some(o) + } + None => None + } + } +} + +impl<'o,'tcx> fmt::Debug for TraitObligationStack<'o,'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "TraitObligationStack({:?})", self.obligation) + } +} + +impl EvaluationResult { + fn may_apply(&self) -> bool { + match *self { + EvaluatedToOk | + EvaluatedToAmbig | + EvaluatedToUnknown => true, + + EvaluatedToErr => false + } + } +} + +impl MethodMatchResult { + pub fn may_apply(&self) -> bool { + match *self { + MethodMatched(_) => true, + MethodAmbiguous(_) => true, + MethodDidNotMatch => false, + } + } +} diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs new file mode 100644 index 00000000000..e0ce54115eb --- /dev/null +++ b/src/librustc/traits/specialize/mod.rs @@ -0,0 +1,221 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Logic and data structures related to impl specialization, explained in +// greater detail below. +// +// At the moment, this implementation support only the simple "chain" rule: +// If any two impls overlap, one must be a strict subset of the other. +// +// See traits/README.md for a bit more detail on how specialization +// fits together with the rest of the trait machinery. + +use super::{SelectionContext, FulfillmentContext}; +use super::util::{fresh_type_vars_for_impl, impl_trait_ref_and_oblig}; + +use middle::cstore::CrateStore; +use middle::def_id::DefId; +use infer::{self, InferCtxt, TypeOrigin}; +use middle::region; +use ty::subst::{Subst, Substs}; +use traits::{self, ProjectionMode, ObligationCause, Normalized}; +use ty::{self, TyCtxt}; +use syntax::codemap::DUMMY_SP; + +pub mod specialization_graph; + +/// Information pertinent to an overlapping impl error. +pub struct Overlap<'a, 'tcx: 'a> { + pub in_context: InferCtxt<'a, 'tcx>, + pub with_impl: DefId, + pub on_trait_ref: ty::TraitRef<'tcx>, +} + +/// Given a subst for the requested impl, translate it to a subst +/// appropriate for the actual item definition (whether it be in that impl, +/// a parent impl, or the trait). +/// When we have selected one impl, but are actually using item definitions from +/// a parent impl providing a default, we need a way to translate between the +/// type parameters of the two impls. Here the `source_impl` is the one we've +/// selected, and `source_substs` is a substitution of its generics (and +/// possibly some relevant `FnSpace` variables as well). And `target_node` is +/// the impl/trait we're actually going to get the definition from. The resulting +/// substitution will map from `target_node`'s generics to `source_impl`'s +/// generics as instantiated by `source_subst`. +/// +/// For example, consider the following scenario: +/// +/// ```rust +/// trait Foo { ... } +/// impl Foo for (T, U) { ... } // target impl +/// impl Foo for (V, V) { ... } // source impl +/// ``` +/// +/// Suppose we have selected "source impl" with `V` instantiated with `u32`. +/// This function will produce a substitution with `T` and `U` both mapping to `u32`. +/// +/// Where clauses add some trickiness here, because they can be used to "define" +/// an argument indirectly: +/// +/// ```rust +/// impl<'a, I, T: 'a> Iterator for Cloned +/// where I: Iterator, T: Clone +/// ``` +/// +/// In a case like this, the substitution for `T` is determined indirectly, +/// through associated type projection. We deal with such cases by using +/// *fulfillment* to relate the two impls, requiring that all projections are +/// resolved. +pub fn translate_substs<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + source_impl: DefId, + source_substs: &'tcx Substs<'tcx>, + target_node: specialization_graph::Node) + -> &'tcx Substs<'tcx> { + let source_trait_ref = infcx.tcx + .impl_trait_ref(source_impl) + .unwrap() + .subst(infcx.tcx, &source_substs); + + // translate the Self and TyParam parts of the substitution, since those + // vary across impls + let target_substs = match target_node { + specialization_graph::Node::Impl(target_impl) => { + // no need to translate if we're targetting the impl we started with + if source_impl == target_impl { + return source_substs; + } + + fulfill_implication(infcx, source_trait_ref, target_impl).unwrap_or_else(|_| { + infcx.tcx + .sess + .bug("When translating substitutions for specialization, the expected \ + specializaiton failed to hold") + }) + } + specialization_graph::Node::Trait(..) => source_trait_ref.substs.clone(), + }; + + // directly inherent the method generics, since those do not vary across impls + infcx.tcx.mk_substs(target_substs.with_method_from_subst(source_substs)) +} + +/// Is impl1 a specialization of impl2? +/// +/// Specialization is determined by the sets of types to which the impls apply; +/// impl1 specializes impl2 if it applies to a subset of the types impl2 applies +/// to. +pub fn specializes(tcx: &TyCtxt, impl1_def_id: DefId, impl2_def_id: DefId) -> bool { + // The feature gate should prevent introducing new specializations, but not + // taking advantage of upstream ones. + if !tcx.sess.features.borrow().specialization && + (impl1_def_id.is_local() || impl2_def_id.is_local()) { + return false; + } + + // We determine whether there's a subset relationship by: + // + // - skolemizing impl1, + // - assuming the where clauses for impl1, + // - instantiating impl2 with fresh inference variables, + // - unifying, + // - attempting to prove the where clauses for impl2 + // + // The last three steps are encapsulated in `fulfill_implication`. + // + // See RFC 1210 for more details and justification. + + // Currently we do not allow e.g. a negative impl to specialize a positive one + if tcx.trait_impl_polarity(impl1_def_id) != tcx.trait_impl_polarity(impl2_def_id) { + return false; + } + + let mut infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables, ProjectionMode::Topmost); + + // create a parameter environment corresponding to a (skolemized) instantiation of impl1 + let scheme = tcx.lookup_item_type(impl1_def_id); + let predicates = tcx.lookup_predicates(impl1_def_id); + let mut penv = tcx.construct_parameter_environment(DUMMY_SP, + &scheme.generics, + &predicates, + region::DUMMY_CODE_EXTENT); + let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id) + .unwrap() + .subst(tcx, &penv.free_substs); + + // Normalize the trait reference, adding any obligations that arise into the impl1 assumptions + let Normalized { value: impl1_trait_ref, obligations: normalization_obligations } = { + let selcx = &mut SelectionContext::new(&infcx); + traits::normalize(selcx, ObligationCause::dummy(), &impl1_trait_ref) + }; + penv.caller_bounds.extend(normalization_obligations.into_iter().map(|o| o.predicate)); + + // Install the parameter environment, taking the predicates of impl1 as assumptions: + infcx.parameter_environment = penv; + + // Attempt to prove that impl2 applies, given all of the above. + fulfill_implication(&infcx, impl1_trait_ref, impl2_def_id).is_ok() +} + +/// Attempt to fulfill all obligations of `target_impl` after unification with +/// `source_trait_ref`. If successful, returns a substitution for *all* the +/// generics of `target_impl`, including both those needed to unify with +/// `source_trait_ref` and those whose identity is determined via a where +/// clause in the impl. +fn fulfill_implication<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + source_trait_ref: ty::TraitRef<'tcx>, + target_impl: DefId) + -> Result, ()> { + infcx.commit_if_ok(|_| { + let selcx = &mut SelectionContext::new(&infcx); + let target_substs = fresh_type_vars_for_impl(&infcx, DUMMY_SP, target_impl); + let (target_trait_ref, obligations) = impl_trait_ref_and_oblig(selcx, + target_impl, + &target_substs); + + // do the impls unify? If not, no specialization. + if let Err(_) = infer::mk_eq_trait_refs(&infcx, + true, + TypeOrigin::Misc(DUMMY_SP), + source_trait_ref, + target_trait_ref) { + debug!("fulfill_implication: {:?} does not unify with {:?}", + source_trait_ref, + target_trait_ref); + return Err(()); + } + + // attempt to prove all of the predicates for impl2 given those for impl1 + // (which are packed up in penv) + + let mut fulfill_cx = FulfillmentContext::new(); + for oblig in obligations.into_iter() { + fulfill_cx.register_predicate_obligation(&infcx, oblig); + } + + if let Err(errors) = infer::drain_fulfillment_cx(&infcx, &mut fulfill_cx, &()) { + // no dice! + debug!("fulfill_implication: for impls on {:?} and {:?}, could not fulfill: {:?} given \ + {:?}", + source_trait_ref, + target_trait_ref, + errors, + infcx.parameter_environment.caller_bounds); + Err(()) + } else { + debug!("fulfill_implication: an impl for {:?} specializes {:?}", + source_trait_ref, + target_trait_ref); + + // Now resolve the *substitution* we built for the target earlier, replacing + // the inference variables inside with whatever we got from fulfillment. + Ok(infcx.resolve_type_vars_if_possible(&target_substs)) + } + }) +} diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs new file mode 100644 index 00000000000..eaafeb1a969 --- /dev/null +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -0,0 +1,393 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::cell; +use std::rc::Rc; + +use super::{Overlap, specializes}; + +use middle::cstore::CrateStore; +use middle::def_id::DefId; +use infer; +use traits::{self, ProjectionMode}; +use ty::{self, TyCtxt, ImplOrTraitItem, TraitDef, TypeFoldable}; +use syntax::ast::Name; +use util::nodemap::DefIdMap; + +/// A per-trait graph of impls in specialization order. At the moment, this +/// graph forms a tree rooted with the trait itself, with all other nodes +/// representing impls, and parent-child relationships representing +/// specializations. +/// +/// The graph provides two key services: +/// +/// - Construction, which implicitly checks for overlapping impls (i.e., impls +/// that overlap but where neither specializes the other -- an artifact of the +/// simple "chain" rule. +/// +/// - Parent extraction. In particular, the graph can give you the *immediate* +/// parents of a given specializing impl, which is needed for extracting +/// default items amongst other thigns. In the simple "chain" rule, every impl +/// has at most one parent. +pub struct Graph { + // all impls have a parent; the "root" impls have as their parent the def_id + // of the trait + parent: DefIdMap, + + // the "root" impls are found by looking up the trait's def_id. + children: DefIdMap>, +} + +impl Graph { + pub fn new() -> Graph { + Graph { + parent: Default::default(), + children: Default::default(), + } + } + + /// Insert a local impl into the specialization graph. If an existing impl + /// conflicts with it (has overlap, but neither specializes the other), + /// information about the area of overlap is returned in the `Err`. + pub fn insert<'a, 'tcx>(&mut self, + tcx: &'a TyCtxt<'tcx>, + impl_def_id: DefId) + -> Result<(), Overlap<'a, 'tcx>> { + assert!(impl_def_id.is_local()); + + let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); + let trait_def_id = trait_ref.def_id; + + debug!("insert({:?}): inserting TraitRef {:?} into specialization graph", + impl_def_id, trait_ref); + + // if the reference itself contains an earlier error (e.g., due to a + // resolution failure), then we just insert the impl at the top level of + // the graph and claim that there's no overlap (in order to supress + // bogus errors). + if trait_ref.references_error() { + debug!("insert: inserting dummy node for erroneous TraitRef {:?}, \ + impl_def_id={:?}, trait_def_id={:?}", + trait_ref, impl_def_id, trait_def_id); + + self.parent.insert(impl_def_id, trait_def_id); + self.children.entry(trait_def_id).or_insert(vec![]).push(impl_def_id); + return Ok(()); + } + + let mut parent = trait_def_id; + + // Ugly hack around borrowck limitations. Assigned only in the case + // where we bump downward an existing node in the graph. + let child_to_insert; + + 'descend: loop { + let mut possible_siblings = self.children.entry(parent).or_insert(vec![]); + + for slot in possible_siblings.iter_mut() { + let possible_sibling = *slot; + + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, ProjectionMode::Topmost); + let overlap = traits::overlapping_impls(&infcx, possible_sibling, impl_def_id); + + if let Some(impl_header) = overlap { + let le = specializes(tcx, impl_def_id, possible_sibling); + let ge = specializes(tcx, possible_sibling, impl_def_id); + + if le && !ge { + debug!("descending as child of TraitRef {:?}", + tcx.impl_trait_ref(possible_sibling).unwrap()); + + // the impl specializes possible_sibling + parent = possible_sibling; + continue 'descend; + } else if ge && !le { + debug!("placing as parent of TraitRef {:?}", + tcx.impl_trait_ref(possible_sibling).unwrap()); + + // possible_sibling specializes the impl + *slot = impl_def_id; + self.parent.insert(impl_def_id, parent); + self.parent.insert(possible_sibling, impl_def_id); + // we have to defer the insertion, because we can't + // relinquish the borrow of `self.children` + child_to_insert = possible_sibling; + break 'descend; + } else { + // overlap, but no specialization; error out + return Err(Overlap { + with_impl: possible_sibling, + on_trait_ref: impl_header.trait_ref.unwrap(), + in_context: infcx, + }); + } + } + } + + // no overlap with any potential siblings, so add as a new sibling + debug!("placing as new sibling"); + self.parent.insert(impl_def_id, parent); + possible_siblings.push(impl_def_id); + return Ok(()); + } + + self.children.insert(impl_def_id, vec![child_to_insert]); + Ok(()) + } + + /// Insert cached metadata mapping from a child impl back to its parent. + pub fn record_impl_from_cstore(&mut self, parent: DefId, child: DefId) { + if self.parent.insert(child, parent).is_some() { + panic!("When recording an impl from the crate store, information about its parent \ + was already present."); + } + + self.children.entry(parent).or_insert(vec![]).push(child); + } + + /// The parent of a given impl, which is the def id of the trait when the + /// impl is a "specialization root". + pub fn parent(&self, child: DefId) -> DefId { + *self.parent.get(&child).unwrap() + } +} + +/// A node in the specialization graph is either an impl or a trait +/// definition; either can serve as a source of item definitions. +/// There is always exactly one trait definition node: the root. +#[derive(Debug, Copy, Clone)] +pub enum Node { + Impl(DefId), + Trait(DefId), +} + +impl Node { + pub fn is_from_trait(&self) -> bool { + match *self { + Node::Trait(..) => true, + _ => false, + } + } + + /// Iterate over the items defined directly by the given (impl or trait) node. + pub fn items<'a, 'tcx>(&self, tcx: &'a TyCtxt<'tcx>) -> NodeItems<'a, 'tcx> { + match *self { + Node::Impl(impl_def_id) => { + NodeItems::Impl { + tcx: tcx, + items: cell::Ref::map(tcx.impl_items.borrow(), + |impl_items| &impl_items[&impl_def_id]), + idx: 0, + } + } + Node::Trait(trait_def_id) => { + NodeItems::Trait { + items: tcx.trait_items(trait_def_id).clone(), + idx: 0, + } + } + } + } + + pub fn def_id(&self) -> DefId { + match *self { + Node::Impl(did) => did, + Node::Trait(did) => did, + } + } +} + +/// An iterator over the items defined within a trait or impl. +pub enum NodeItems<'a, 'tcx: 'a> { + Impl { + tcx: &'a TyCtxt<'tcx>, + items: cell::Ref<'a, Vec>, + idx: usize, + }, + Trait { + items: Rc>>, + idx: usize, + }, +} + +impl<'a, 'tcx> Iterator for NodeItems<'a, 'tcx> { + type Item = ImplOrTraitItem<'tcx>; + fn next(&mut self) -> Option> { + match *self { + NodeItems::Impl { tcx, ref items, ref mut idx } => { + let items_table = tcx.impl_or_trait_items.borrow(); + if *idx < items.len() { + let item_def_id = items[*idx].def_id(); + let item = items_table[&item_def_id].clone(); + *idx += 1; + Some(item) + } else { + None + } + } + NodeItems::Trait { ref items, ref mut idx } => { + if *idx < items.len() { + let item = items[*idx].clone(); + *idx += 1; + Some(item) + } else { + None + } + } + } + } +} + +pub struct Ancestors<'a, 'tcx: 'a> { + trait_def: &'a TraitDef<'tcx>, + current_source: Option, +} + +impl<'a, 'tcx> Iterator for Ancestors<'a, 'tcx> { + type Item = Node; + fn next(&mut self) -> Option { + let cur = self.current_source.take(); + if let Some(Node::Impl(cur_impl)) = cur { + let parent = self.trait_def.specialization_graph.borrow().parent(cur_impl); + if parent == self.trait_def.def_id() { + self.current_source = Some(Node::Trait(parent)); + } else { + self.current_source = Some(Node::Impl(parent)); + } + } + cur + } +} + +pub struct NodeItem { + pub node: Node, + pub item: T, +} + +impl NodeItem { + pub fn map U>(self, f: F) -> NodeItem { + NodeItem { + node: self.node, + item: f(self.item), + } + } +} + +pub struct TypeDefs<'a, 'tcx: 'a> { + // generally only invoked once or twice, so the box doesn't hurt + iter: Box>>> + 'a>, +} + +impl<'a, 'tcx> Iterator for TypeDefs<'a, 'tcx> { + type Item = NodeItem>>; + fn next(&mut self) -> Option { + self.iter.next() + } +} + +pub struct FnDefs<'a, 'tcx: 'a> { + // generally only invoked once or twice, so the box doesn't hurt + iter: Box>>> + 'a>, +} + +impl<'a, 'tcx> Iterator for FnDefs<'a, 'tcx> { + type Item = NodeItem>>; + fn next(&mut self) -> Option { + self.iter.next() + } +} + +pub struct ConstDefs<'a, 'tcx: 'a> { + // generally only invoked once or twice, so the box doesn't hurt + iter: Box>>> + 'a>, +} + +impl<'a, 'tcx> Iterator for ConstDefs<'a, 'tcx> { + type Item = NodeItem>>; + fn next(&mut self) -> Option { + self.iter.next() + } +} + +impl<'a, 'tcx> Ancestors<'a, 'tcx> { + /// Search the items from the given ancestors, returning each type definition + /// with the given name. + pub fn type_defs(self, tcx: &'a TyCtxt<'tcx>, name: Name) -> TypeDefs<'a, 'tcx> { + let iter = self.flat_map(move |node| { + node.items(tcx) + .filter_map(move |item| { + if let ty::TypeTraitItem(assoc_ty) = item { + if assoc_ty.name == name { + return Some(NodeItem { + node: node, + item: assoc_ty, + }); + } + } + None + }) + + }); + TypeDefs { iter: Box::new(iter) } + } + + /// Search the items from the given ancestors, returning each fn definition + /// with the given name. + pub fn fn_defs(self, tcx: &'a TyCtxt<'tcx>, name: Name) -> FnDefs<'a, 'tcx> { + let iter = self.flat_map(move |node| { + node.items(tcx) + .filter_map(move |item| { + if let ty::MethodTraitItem(method) = item { + if method.name == name { + return Some(NodeItem { + node: node, + item: method, + }); + } + } + None + }) + + }); + FnDefs { iter: Box::new(iter) } + } + + /// Search the items from the given ancestors, returning each const + /// definition with the given name. + pub fn const_defs(self, tcx: &'a TyCtxt<'tcx>, name: Name) -> ConstDefs<'a, 'tcx> { + let iter = self.flat_map(move |node| { + node.items(tcx) + .filter_map(move |item| { + if let ty::ConstTraitItem(konst) = item { + if konst.name == name { + return Some(NodeItem { + node: node, + item: konst, + }); + } + } + None + }) + + }); + ConstDefs { iter: Box::new(iter) } + } +} + +/// Walk up the specialization ancestors of a given impl, starting with that +/// impl itself. +pub fn ancestors<'a, 'tcx>(trait_def: &'a TraitDef<'tcx>, + start_from_impl: DefId) + -> Ancestors<'a, 'tcx> { + Ancestors { + trait_def: trait_def, + current_source: Some(Node::Impl(start_from_impl)), + } +} diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs new file mode 100644 index 00000000000..367e5f32ba3 --- /dev/null +++ b/src/librustc/traits/structural_impls.rs @@ -0,0 +1,256 @@ +// Copyright 2012-2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use traits; +use traits::project::Normalized; +use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; + +use std::fmt; + +// structural impls for the structs in traits + +impl<'tcx, T: fmt::Debug> fmt::Debug for Normalized<'tcx, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Normalized({:?},{:?})", + self.value, + self.obligations) + } +} + +impl<'tcx> fmt::Debug for traits::RegionObligation<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "RegionObligation(sub_region={:?}, sup_type={:?})", + self.sub_region, + self.sup_type) + } +} +impl<'tcx, O: fmt::Debug> fmt::Debug for traits::Obligation<'tcx, O> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Obligation(predicate={:?},depth={})", + self.predicate, + self.recursion_depth) + } +} + +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::Vtable<'tcx, N> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + super::VtableImpl(ref v) => + write!(f, "{:?}", v), + + super::VtableDefaultImpl(ref t) => + write!(f, "{:?}", t), + + super::VtableClosure(ref d) => + write!(f, "{:?}", d), + + super::VtableFnPointer(ref d) => + write!(f, "VtableFnPointer({:?})", d), + + super::VtableObject(ref d) => + write!(f, "{:?}", d), + + super::VtableParam(ref n) => + write!(f, "VtableParam({:?})", n), + + super::VtableBuiltin(ref d) => + write!(f, "{:?}", d) + } + } +} + +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableImplData<'tcx, N> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "VtableImpl(impl_def_id={:?}, substs={:?}, nested={:?})", + self.impl_def_id, + self.substs, + self.nested) + } +} + +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableClosureData<'tcx, N> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "VtableClosure(closure_def_id={:?}, substs={:?}, nested={:?})", + self.closure_def_id, + self.substs, + self.nested) + } +} + +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableBuiltinData { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "VtableBuiltin(nested={:?})", self.nested) + } +} + +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableDefaultImplData { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "VtableDefaultImplData(trait_def_id={:?}, nested={:?})", + self.trait_def_id, + self.nested) + } +} + +impl<'tcx> fmt::Debug for traits::VtableObjectData<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "VtableObject(upcast={:?}, vtable_base={})", + self.upcast_trait_ref, + self.vtable_base) + } +} + +impl<'tcx> fmt::Debug for traits::FulfillmentError<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "FulfillmentError({:?},{:?})", + self.obligation, + self.code) + } +} + +impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + super::CodeSelectionError(ref e) => write!(f, "{:?}", e), + super::CodeProjectionError(ref e) => write!(f, "{:?}", e), + super::CodeAmbiguity => write!(f, "Ambiguity") + } + } +} + +impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "MismatchedProjectionTypes({:?})", self.err) + } +} + +impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx, O> +{ + fn super_fold_with>(&self, folder: &mut F) -> Self { + traits::Obligation { + cause: self.cause.clone(), + recursion_depth: self.recursion_depth, + predicate: self.predicate.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.predicate.visit_with(visitor) + } +} + +impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableImplData<'tcx, N> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + let substs = self.substs.fold_with(folder); + traits::VtableImplData { + impl_def_id: self.impl_def_id, + substs: folder.tcx().mk_substs(substs), + nested: self.nested.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.substs.visit_with(visitor) || self.nested.visit_with(visitor) + } +} + +impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableClosureData<'tcx, N> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + traits::VtableClosureData { + closure_def_id: self.closure_def_id, + substs: self.substs.fold_with(folder), + nested: self.nested.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.substs.visit_with(visitor) || self.nested.visit_with(visitor) + } +} + +impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableDefaultImplData { + fn super_fold_with>(&self, folder: &mut F) -> Self { + traits::VtableDefaultImplData { + trait_def_id: self.trait_def_id, + nested: self.nested.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.nested.visit_with(visitor) + } +} + +impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableBuiltinData { + fn super_fold_with>(&self, folder: &mut F) -> Self { + traits::VtableBuiltinData { + nested: self.nested.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.nested.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + traits::VtableObjectData { + upcast_trait_ref: self.upcast_trait_ref.fold_with(folder), + vtable_base: self.vtable_base + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.upcast_trait_ref.visit_with(visitor) + } +} + +impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + match *self { + traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)), + traits::VtableDefaultImpl(ref t) => traits::VtableDefaultImpl(t.fold_with(folder)), + traits::VtableClosure(ref d) => { + traits::VtableClosure(d.fold_with(folder)) + } + traits::VtableFnPointer(ref d) => { + traits::VtableFnPointer(d.fold_with(folder)) + } + traits::VtableParam(ref n) => traits::VtableParam(n.fold_with(folder)), + traits::VtableBuiltin(ref d) => traits::VtableBuiltin(d.fold_with(folder)), + traits::VtableObject(ref d) => traits::VtableObject(d.fold_with(folder)), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + match *self { + traits::VtableImpl(ref v) => v.visit_with(visitor), + traits::VtableDefaultImpl(ref t) => t.visit_with(visitor), + traits::VtableClosure(ref d) => d.visit_with(visitor), + traits::VtableFnPointer(ref d) => d.visit_with(visitor), + traits::VtableParam(ref n) => n.visit_with(visitor), + traits::VtableBuiltin(ref d) => d.visit_with(visitor), + traits::VtableObject(ref d) => d.visit_with(visitor), + } + } +} + +impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Normalized<'tcx, T> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + Normalized { + value: self.value.fold_with(folder), + obligations: self.obligations.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.value.visit_with(visitor) || self.obligations.visit_with(visitor) + } +} diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs new file mode 100644 index 00000000000..f339b6e50ce --- /dev/null +++ b/src/librustc/traits/util.rs @@ -0,0 +1,508 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use middle::def_id::DefId; +use infer::InferCtxt; +use ty::subst::{Subst, Substs}; +use ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef}; +use syntax::codemap::Span; +use util::common::ErrorReported; +use util::nodemap::FnvHashSet; + +use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext, Normalized}; + +struct PredicateSet<'a,'tcx:'a> { + tcx: &'a TyCtxt<'tcx>, + set: FnvHashSet>, +} + +impl<'a,'tcx> PredicateSet<'a,'tcx> { + fn new(tcx: &'a TyCtxt<'tcx>) -> PredicateSet<'a,'tcx> { + PredicateSet { tcx: tcx, set: FnvHashSet() } + } + + fn insert(&mut self, pred: &ty::Predicate<'tcx>) -> bool { + // We have to be careful here because we want + // + // for<'a> Foo<&'a int> + // + // and + // + // for<'b> Foo<&'b int> + // + // to be considered equivalent. So normalize all late-bound + // regions before we throw things into the underlying set. + let normalized_pred = match *pred { + ty::Predicate::Trait(ref data) => + ty::Predicate::Trait(self.tcx.anonymize_late_bound_regions(data)), + + ty::Predicate::Equate(ref data) => + ty::Predicate::Equate(self.tcx.anonymize_late_bound_regions(data)), + + ty::Predicate::RegionOutlives(ref data) => + ty::Predicate::RegionOutlives(self.tcx.anonymize_late_bound_regions(data)), + + ty::Predicate::TypeOutlives(ref data) => + ty::Predicate::TypeOutlives(self.tcx.anonymize_late_bound_regions(data)), + + ty::Predicate::Projection(ref data) => + ty::Predicate::Projection(self.tcx.anonymize_late_bound_regions(data)), + + ty::Predicate::WellFormed(data) => + ty::Predicate::WellFormed(data), + + ty::Predicate::ObjectSafe(data) => + ty::Predicate::ObjectSafe(data), + }; + self.set.insert(normalized_pred) + } +} + +/////////////////////////////////////////////////////////////////////////// +// `Elaboration` iterator +/////////////////////////////////////////////////////////////////////////// + +/// "Elaboration" is the process of identifying all the predicates that +/// are implied by a source predicate. Currently this basically means +/// walking the "supertraits" and other similar assumptions. For +/// example, if we know that `T : Ord`, the elaborator would deduce +/// that `T : PartialOrd` holds as well. Similarly, if we have `trait +/// Foo : 'static`, and we know that `T : Foo`, then we know that `T : +/// 'static`. +pub struct Elaborator<'cx, 'tcx:'cx> { + tcx: &'cx TyCtxt<'tcx>, + stack: Vec>, + visited: PredicateSet<'cx,'tcx>, +} + +pub fn elaborate_trait_ref<'cx, 'tcx>( + tcx: &'cx TyCtxt<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>) + -> Elaborator<'cx, 'tcx> +{ + elaborate_predicates(tcx, vec![trait_ref.to_predicate()]) +} + +pub fn elaborate_trait_refs<'cx, 'tcx>( + tcx: &'cx TyCtxt<'tcx>, + trait_refs: &[ty::PolyTraitRef<'tcx>]) + -> Elaborator<'cx, 'tcx> +{ + let predicates = trait_refs.iter() + .map(|trait_ref| trait_ref.to_predicate()) + .collect(); + elaborate_predicates(tcx, predicates) +} + +pub fn elaborate_predicates<'cx, 'tcx>( + tcx: &'cx TyCtxt<'tcx>, + mut predicates: Vec>) + -> Elaborator<'cx, 'tcx> +{ + let mut visited = PredicateSet::new(tcx); + predicates.retain(|pred| visited.insert(pred)); + Elaborator { tcx: tcx, stack: predicates, visited: visited } +} + +impl<'cx, 'tcx> Elaborator<'cx, 'tcx> { + pub fn filter_to_traits(self) -> FilterToTraits> { + FilterToTraits::new(self) + } + + fn push(&mut self, predicate: &ty::Predicate<'tcx>) { + match *predicate { + ty::Predicate::Trait(ref data) => { + // Predicates declared on the trait. + let predicates = self.tcx.lookup_super_predicates(data.def_id()); + + let mut predicates: Vec<_> = + predicates.predicates + .iter() + .map(|p| p.subst_supertrait(self.tcx, &data.to_poly_trait_ref())) + .collect(); + + debug!("super_predicates: data={:?} predicates={:?}", + data, predicates); + + // Only keep those bounds that we haven't already + // seen. This is necessary to prevent infinite + // recursion in some cases. One common case is when + // people define `trait Sized: Sized { }` rather than `trait + // Sized { }`. + predicates.retain(|r| self.visited.insert(r)); + + self.stack.extend(predicates); + } + ty::Predicate::WellFormed(..) => { + // Currently, we do not elaborate WF predicates, + // although we easily could. + } + ty::Predicate::ObjectSafe(..) => { + // Currently, we do not elaborate object-safe + // predicates. + } + ty::Predicate::Equate(..) => { + // Currently, we do not "elaborate" predicates like + // `X == Y`, though conceivably we might. For example, + // `&X == &Y` implies that `X == Y`. + } + ty::Predicate::Projection(..) => { + // Nothing to elaborate in a projection predicate. + } + ty::Predicate::RegionOutlives(..) | + ty::Predicate::TypeOutlives(..) => { + // Currently, we do not "elaborate" predicates like + // `'a : 'b` or `T : 'a`. We could conceivably do + // more here. For example, + // + // &'a int : 'b + // + // implies that + // + // 'a : 'b + // + // and we could get even more if we took WF + // constraints into account. For example, + // + // &'a &'b int : 'c + // + // implies that + // + // 'b : 'a + // 'a : 'c + } + } + } +} + +impl<'cx, 'tcx> Iterator for Elaborator<'cx, 'tcx> { + type Item = ty::Predicate<'tcx>; + + fn next(&mut self) -> Option> { + // Extract next item from top-most stack frame, if any. + let next_predicate = match self.stack.pop() { + Some(predicate) => predicate, + None => { + // No more stack frames. Done. + return None; + } + }; + self.push(&next_predicate); + return Some(next_predicate); + } +} + +/////////////////////////////////////////////////////////////////////////// +// Supertrait iterator +/////////////////////////////////////////////////////////////////////////// + +pub type Supertraits<'cx, 'tcx> = FilterToTraits>; + +pub fn supertraits<'cx, 'tcx>(tcx: &'cx TyCtxt<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>) + -> Supertraits<'cx, 'tcx> +{ + elaborate_trait_ref(tcx, trait_ref).filter_to_traits() +} + +pub fn transitive_bounds<'cx, 'tcx>(tcx: &'cx TyCtxt<'tcx>, + bounds: &[ty::PolyTraitRef<'tcx>]) + -> Supertraits<'cx, 'tcx> +{ + elaborate_trait_refs(tcx, bounds).filter_to_traits() +} + +/////////////////////////////////////////////////////////////////////////// +// Iterator over def-ids of supertraits + +pub struct SupertraitDefIds<'cx, 'tcx:'cx> { + tcx: &'cx TyCtxt<'tcx>, + stack: Vec, + visited: FnvHashSet, +} + +pub fn supertrait_def_ids<'cx, 'tcx>(tcx: &'cx TyCtxt<'tcx>, + trait_def_id: DefId) + -> SupertraitDefIds<'cx, 'tcx> +{ + SupertraitDefIds { + tcx: tcx, + stack: vec![trait_def_id], + visited: Some(trait_def_id).into_iter().collect(), + } +} + +impl<'cx, 'tcx> Iterator for SupertraitDefIds<'cx, 'tcx> { + type Item = DefId; + + fn next(&mut self) -> Option { + let def_id = match self.stack.pop() { + Some(def_id) => def_id, + None => { return None; } + }; + + let predicates = self.tcx.lookup_super_predicates(def_id); + let visited = &mut self.visited; + self.stack.extend( + predicates.predicates + .iter() + .filter_map(|p| p.to_opt_poly_trait_ref()) + .map(|t| t.def_id()) + .filter(|&super_def_id| visited.insert(super_def_id))); + Some(def_id) + } +} + +/////////////////////////////////////////////////////////////////////////// +// Other +/////////////////////////////////////////////////////////////////////////// + +/// A filter around an iterator of predicates that makes it yield up +/// just trait references. +pub struct FilterToTraits { + base_iterator: I +} + +impl FilterToTraits { + fn new(base: I) -> FilterToTraits { + FilterToTraits { base_iterator: base } + } +} + +impl<'tcx,I:Iterator>> Iterator for FilterToTraits { + type Item = ty::PolyTraitRef<'tcx>; + + fn next(&mut self) -> Option> { + loop { + match self.base_iterator.next() { + None => { + return None; + } + Some(ty::Predicate::Trait(data)) => { + return Some(data.to_poly_trait_ref()); + } + Some(_) => { + } + } + } + } +} + +/////////////////////////////////////////////////////////////////////////// +// Other +/////////////////////////////////////////////////////////////////////////// + +/// Instantiate all bound parameters of the impl with the given substs, +/// returning the resulting trait ref and all obligations that arise. +/// The obligations are closed under normalization. +pub fn impl_trait_ref_and_oblig<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, + impl_def_id: DefId, + impl_substs: &Substs<'tcx>) + -> (ty::TraitRef<'tcx>, + Vec>) +{ + let impl_trait_ref = + selcx.tcx().impl_trait_ref(impl_def_id).unwrap(); + let impl_trait_ref = + impl_trait_ref.subst(selcx.tcx(), impl_substs); + let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } = + super::normalize(selcx, ObligationCause::dummy(), &impl_trait_ref); + + let predicates = selcx.tcx().lookup_predicates(impl_def_id); + let predicates = predicates.instantiate(selcx.tcx(), impl_substs); + let Normalized { value: predicates, obligations: normalization_obligations2 } = + super::normalize(selcx, ObligationCause::dummy(), &predicates); + let impl_obligations = + predicates_for_generics(ObligationCause::dummy(), 0, &predicates); + + let impl_obligations: Vec<_> = + impl_obligations.into_iter() + .chain(normalization_obligations1) + .chain(normalization_obligations2) + .collect(); + + (impl_trait_ref, impl_obligations) +} + +// determine the `self` type, using fresh variables for all variables +// declared on the impl declaration e.g., `impl for Box<[(A,B)]>` +// would return ($0, $1) where $0 and $1 are freshly instantiated type +// variables. +pub fn fresh_type_vars_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + span: Span, + impl_def_id: DefId) + -> Substs<'tcx> +{ + let tcx = infcx.tcx; + let impl_generics = tcx.lookup_item_type(impl_def_id).generics; + infcx.fresh_substs_for_generics(span, &impl_generics) +} + +/// See `super::obligations_for_generics` +pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>, + recursion_depth: usize, + generic_bounds: &ty::InstantiatedPredicates<'tcx>) + -> Vec> +{ + debug!("predicates_for_generics(generic_bounds={:?})", + generic_bounds); + + generic_bounds.predicates.iter().map(|predicate| { + Obligation { cause: cause.clone(), + recursion_depth: recursion_depth, + predicate: predicate.clone() } + }).collect() +} + +pub fn trait_ref_for_builtin_bound<'tcx>( + tcx: &TyCtxt<'tcx>, + builtin_bound: ty::BuiltinBound, + param_ty: Ty<'tcx>) + -> Result, ErrorReported> +{ + match tcx.lang_items.from_builtin_kind(builtin_bound) { + Ok(def_id) => { + Ok(ty::TraitRef { + def_id: def_id, + substs: tcx.mk_substs(Substs::empty().with_self_ty(param_ty)) + }) + } + Err(e) => { + tcx.sess.err(&e); + Err(ErrorReported) + } + } +} + +pub fn predicate_for_trait_ref<'tcx>( + cause: ObligationCause<'tcx>, + trait_ref: ty::TraitRef<'tcx>, + recursion_depth: usize) + -> PredicateObligation<'tcx> +{ + Obligation { + cause: cause, + recursion_depth: recursion_depth, + predicate: trait_ref.to_predicate(), + } +} + +pub fn predicate_for_trait_def<'tcx>( + tcx: &TyCtxt<'tcx>, + cause: ObligationCause<'tcx>, + trait_def_id: DefId, + recursion_depth: usize, + param_ty: Ty<'tcx>, + ty_params: Vec>) + -> PredicateObligation<'tcx> +{ + let trait_ref = ty::TraitRef { + def_id: trait_def_id, + substs: tcx.mk_substs(Substs::new_trait(ty_params, vec![], param_ty)) + }; + predicate_for_trait_ref(cause, trait_ref, recursion_depth) +} + +pub fn predicate_for_builtin_bound<'tcx>( + tcx: &TyCtxt<'tcx>, + cause: ObligationCause<'tcx>, + builtin_bound: ty::BuiltinBound, + recursion_depth: usize, + param_ty: Ty<'tcx>) + -> Result, ErrorReported> +{ + let trait_ref = trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty)?; + Ok(predicate_for_trait_ref(cause, trait_ref, recursion_depth)) +} + +/// Cast a trait reference into a reference to one of its super +/// traits; returns `None` if `target_trait_def_id` is not a +/// supertrait. +pub fn upcast<'tcx>(tcx: &TyCtxt<'tcx>, + source_trait_ref: ty::PolyTraitRef<'tcx>, + target_trait_def_id: DefId) + -> Vec> +{ + if source_trait_ref.def_id() == target_trait_def_id { + return vec![source_trait_ref]; // shorcut the most common case + } + + supertraits(tcx, source_trait_ref) + .filter(|r| r.def_id() == target_trait_def_id) + .collect() +} + +/// Given a trait `trait_ref`, returns the number of vtable entries +/// that come from `trait_ref`, excluding its supertraits. Used in +/// computing the vtable base for an upcast trait of a trait object. +pub fn count_own_vtable_entries<'tcx>(tcx: &TyCtxt<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>) + -> usize { + let mut entries = 0; + // Count number of methods and add them to the total offset. + // Skip over associated types and constants. + for trait_item in &tcx.trait_items(trait_ref.def_id())[..] { + if let ty::MethodTraitItem(_) = *trait_item { + entries += 1; + } + } + entries +} + +/// Given an upcast trait object described by `object`, returns the +/// index of the method `method_def_id` (which should be part of +/// `object.upcast_trait_ref`) within the vtable for `object`. +pub fn get_vtable_index_of_object_method<'tcx>(tcx: &TyCtxt<'tcx>, + object: &super::VtableObjectData<'tcx>, + method_def_id: DefId) -> usize { + // Count number of methods preceding the one we are selecting and + // add them to the total offset. + // Skip over associated types and constants. + let mut entries = object.vtable_base; + for trait_item in &tcx.trait_items(object.upcast_trait_ref.def_id())[..] { + if trait_item.def_id() == method_def_id { + // The item with the ID we were given really ought to be a method. + assert!(match *trait_item { + ty::MethodTraitItem(_) => true, + _ => false + }); + + return entries; + } + if let ty::MethodTraitItem(_) = *trait_item { + entries += 1; + } + } + + tcx.sess.bug(&format!("get_vtable_index_of_object_method: {:?} was not found", + method_def_id)); +} + +pub enum TupleArgumentsFlag { Yes, No } + +pub fn closure_trait_ref_and_return_type<'tcx>( + tcx: &TyCtxt<'tcx>, + fn_trait_def_id: DefId, + self_ty: Ty<'tcx>, + sig: &ty::PolyFnSig<'tcx>, + tuple_arguments: TupleArgumentsFlag) + -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)> +{ + let arguments_tuple = match tuple_arguments { + TupleArgumentsFlag::No => sig.0.inputs[0], + TupleArgumentsFlag::Yes => tcx.mk_tup(sig.0.inputs.to_vec()), + }; + let trait_substs = Substs::new_trait(vec![arguments_tuple], vec![], self_ty); + let trait_ref = ty::TraitRef { + def_id: fn_trait_def_id, + substs: tcx.mk_substs(trait_substs), + }; + ty::Binder((trait_ref, sig.0.output.unwrap_or(tcx.mk_nil()))) +} diff --git a/src/librustc/ty/_match.rs b/src/librustc/ty/_match.rs new file mode 100644 index 00000000000..d0ccc3e0fdd --- /dev/null +++ b/src/librustc/ty/_match.rs @@ -0,0 +1,96 @@ +// Copyright 2012 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ty::{self, Ty, TyCtxt}; +use ty::error::TypeError; +use ty::relate::{self, Relate, TypeRelation, RelateResult}; + +/// A type "A" *matches* "B" if the fresh types in B could be +/// substituted with values so as to make it equal to A. Matching is +/// intended to be used only on freshened types, and it basically +/// indicates if the non-freshened versions of A and B could have been +/// unified. +/// +/// It is only an approximation. If it yields false, unification would +/// definitely fail, but a true result doesn't mean unification would +/// succeed. This is because we don't track the "side-constraints" on +/// type variables, nor do we track if the same freshened type appears +/// more than once. To some extent these approximations could be +/// fixed, given effort. +/// +/// Like subtyping, matching is really a binary relation, so the only +/// important thing about the result is Ok/Err. Also, matching never +/// affects any type variables or unification state. +pub struct Match<'a, 'tcx: 'a> { + tcx: &'a TyCtxt<'tcx> +} + +impl<'a, 'tcx> Match<'a, 'tcx> { + pub fn new(tcx: &'a TyCtxt<'tcx>) -> Match<'a, 'tcx> { + Match { tcx: tcx } + } +} + +impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Match<'a, 'tcx> { + fn tag(&self) -> &'static str { "Match" } + fn tcx(&self) -> &'a TyCtxt<'tcx> { self.tcx } + fn a_is_expected(&self) -> bool { true } // irrelevant + + fn relate_with_variance>(&mut self, + _: ty::Variance, + a: &T, + b: &T) + -> RelateResult<'tcx, T> + { + self.relate(a, b) + } + + fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> { + debug!("{}.regions({:?}, {:?})", + self.tag(), + a, + b); + Ok(a) + } + + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + debug!("{}.tys({:?}, {:?})", self.tag(), + a, b); + if a == b { return Ok(a); } + + match (&a.sty, &b.sty) { + (_, &ty::TyInfer(ty::FreshTy(_))) | + (_, &ty::TyInfer(ty::FreshIntTy(_))) | + (_, &ty::TyInfer(ty::FreshFloatTy(_))) => { + Ok(a) + } + + (&ty::TyInfer(_), _) | + (_, &ty::TyInfer(_)) => { + Err(TypeError::Sorts(relate::expected_found(self, &a, &b))) + } + + (&ty::TyError, _) | (_, &ty::TyError) => { + Ok(self.tcx().types.err) + } + + _ => { + relate::super_relate_tys(self, a, b) + } + } + } + + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where T: Relate<'a,'tcx> + { + Ok(ty::Binder(self.relate(a.skip_binder(), b.skip_binder())?)) + } +} diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs new file mode 100644 index 00000000000..dc2117b1ad1 --- /dev/null +++ b/src/librustc/ty/adjustment.rs @@ -0,0 +1,265 @@ +// Copyright 2012-2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use self::AutoAdjustment::*; +pub use self::AutoRef::*; + +use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFoldable}; +use ty::LvaluePreference::{NoPreference}; + +use syntax::ast; +use syntax::codemap::Span; + +use rustc_front::hir; + +#[derive(Copy, Clone)] +pub enum AutoAdjustment<'tcx> { + AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type + AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer + AdjustMutToConstPointer, // go from a mut raw pointer to a const raw pointer + AdjustDerefRef(AutoDerefRef<'tcx>), +} + +/// Represents coercing a pointer to a different kind of pointer - where 'kind' +/// here means either or both of raw vs borrowed vs unique and fat vs thin. +/// +/// We transform pointers by following the following steps in order: +/// 1. Deref the pointer `self.autoderefs` times (may be 0). +/// 2. If `autoref` is `Some(_)`, then take the address and produce either a +/// `&` or `*` pointer. +/// 3. If `unsize` is `Some(_)`, then apply the unsize transformation, +/// which will do things like convert thin pointers to fat +/// pointers, or convert structs containing thin pointers to +/// structs containing fat pointers, or convert between fat +/// pointers. We don't store the details of how the transform is +/// done (in fact, we don't know that, because it might depend on +/// the precise type parameters). We just store the target +/// type. Trans figures out what has to be done at monomorphization +/// time based on the precise source/target type at hand. +/// +/// To make that more concrete, here are some common scenarios: +/// +/// 1. The simplest cases are where the pointer is not adjusted fat vs thin. +/// Here the pointer will be dereferenced N times (where a dereference can +/// happen to raw or borrowed pointers or any smart pointer which implements +/// Deref, including Box<_>). The number of dereferences is given by +/// `autoderefs`. It can then be auto-referenced zero or one times, indicated +/// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is +/// None. +/// +/// 2. A thin-to-fat coercon involves unsizing the underlying data. We start +/// with a thin pointer, deref a number of times, unsize the underlying data, +/// then autoref. The 'unsize' phase may change a fixed length array to a +/// dynamically sized one, a concrete object to a trait object, or statically +/// sized struct to a dyncamically sized one. E.g., &[i32; 4] -> &[i32] is +/// represented by: +/// +/// ``` +/// AutoDerefRef { +/// autoderefs: 1, // &[i32; 4] -> [i32; 4] +/// autoref: Some(AutoPtr), // [i32] -> &[i32] +/// unsize: Some([i32]), // [i32; 4] -> [i32] +/// } +/// ``` +/// +/// Note that for a struct, the 'deep' unsizing of the struct is not recorded. +/// E.g., `struct Foo { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]> +/// The autoderef and -ref are the same as in the above example, but the type +/// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about +/// the underlying conversions from `[i32; 4]` to `[i32]`. +/// +/// 3. Coercing a `Box` to `Box` is an interesting special case. In +/// that case, we have the pointer we need coming in, so there are no +/// autoderefs, and no autoref. Instead we just do the `Unsize` transformation. +/// At some point, of course, `Box` should move out of the compiler, in which +/// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> -> +/// Box<[i32]> is represented by: +/// +/// ``` +/// AutoDerefRef { +/// autoderefs: 0, +/// autoref: None, +/// unsize: Some(Box<[i32]>), +/// } +/// ``` +#[derive(Copy, Clone)] +pub struct AutoDerefRef<'tcx> { + /// Step 1. Apply a number of dereferences, producing an lvalue. + pub autoderefs: usize, + + /// Step 2. Optionally produce a pointer/reference from the value. + pub autoref: Option>, + + /// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to + /// `&[T]`. The stored type is the target pointer type. Note that + /// the source could be a thin or fat pointer. + pub unsize: Option>, +} + +impl<'tcx> AutoAdjustment<'tcx> { + pub fn is_identity(&self) -> bool { + match *self { + AdjustReifyFnPointer | + AdjustUnsafeFnPointer | + AdjustMutToConstPointer => false, + AdjustDerefRef(ref r) => r.is_identity(), + } + } +} +impl<'tcx> AutoDerefRef<'tcx> { + pub fn is_identity(&self) -> bool { + self.autoderefs == 0 && self.unsize.is_none() && self.autoref.is_none() + } +} + + +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum AutoRef<'tcx> { + /// Convert from T to &T. + AutoPtr(&'tcx ty::Region, hir::Mutability), + + /// Convert from T to *T. + /// Value to thin pointer. + AutoUnsafe(hir::Mutability), +} + +#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] +pub enum CustomCoerceUnsized { + /// Records the index of the field being coerced. + Struct(usize) +} + +impl<'tcx> ty::TyS<'tcx> { + /// See `expr_ty_adjusted` + pub fn adjust(&'tcx self, cx: &TyCtxt<'tcx>, + span: Span, + expr_id: ast::NodeId, + adjustment: Option<&AutoAdjustment<'tcx>>, + mut method_type: F) + -> Ty<'tcx> where + F: FnMut(ty::MethodCall) -> Option>, + { + if let ty::TyError = self.sty { + return self; + } + + return match adjustment { + Some(adjustment) => { + match *adjustment { + AdjustReifyFnPointer => { + match self.sty { + ty::TyFnDef(_, _, b) => { + cx.mk_ty(ty::TyFnPtr(b)) + } + _ => { + cx.sess.bug( + &format!("AdjustReifyFnPointer adjustment on non-fn-item: \ + {:?}", self)); + } + } + } + + AdjustUnsafeFnPointer => { + match self.sty { + ty::TyFnPtr(b) => cx.safe_to_unsafe_fn_ty(b), + ref b => { + cx.sess.bug( + &format!("AdjustUnsafeFnPointer adjustment on non-fn-ptr: \ + {:?}", + b)); + } + } + } + + AdjustMutToConstPointer => { + match self.sty { + ty::TyRawPtr(mt) => cx.mk_ptr(ty::TypeAndMut { + ty: mt.ty, + mutbl: hir::MutImmutable + }), + ref b => { + cx.sess.bug( + &format!("AdjustMutToConstPointer on non-raw-ptr: \ + {:?}", + b)); + } + } + } + + AdjustDerefRef(ref adj) => { + let mut adjusted_ty = self; + + if !adjusted_ty.references_error() { + for i in 0..adj.autoderefs { + adjusted_ty = + adjusted_ty.adjust_for_autoderef(cx, + expr_id, + span, + i as u32, + &mut method_type); + } + } + + if let Some(target) = adj.unsize { + target + } else { + adjusted_ty.adjust_for_autoref(cx, adj.autoref) + } + } + } + } + None => self + }; + } + + pub fn adjust_for_autoderef(&'tcx self, + cx: &TyCtxt<'tcx>, + expr_id: ast::NodeId, + expr_span: Span, + autoderef: u32, // how many autoderefs so far? + mut method_type: F) + -> Ty<'tcx> where + F: FnMut(ty::MethodCall) -> Option>, + { + let method_call = ty::MethodCall::autoderef(expr_id, autoderef); + let mut adjusted_ty = self; + if let Some(method_ty) = method_type(method_call) { + // Method calls always have all late-bound regions + // fully instantiated. + let fn_ret = cx.no_late_bound_regions(&method_ty.fn_ret()).unwrap(); + adjusted_ty = fn_ret.unwrap(); + } + match adjusted_ty.builtin_deref(true, NoPreference) { + Some(mt) => mt.ty, + None => { + cx.sess.span_bug( + expr_span, + &format!("the {}th autoderef failed: {}", + autoderef, + adjusted_ty) + ); + } + } + } + + pub fn adjust_for_autoref(&'tcx self, cx: &TyCtxt<'tcx>, + autoref: Option>) + -> Ty<'tcx> { + match autoref { + None => self, + Some(AutoPtr(r, m)) => { + cx.mk_ref(r, TypeAndMut { ty: self, mutbl: m }) + } + Some(AutoUnsafe(m)) => { + cx.mk_ptr(TypeAndMut { ty: self, mutbl: m }) + } + } + } +} diff --git a/src/librustc/ty/cast.rs b/src/librustc/ty/cast.rs new file mode 100644 index 00000000000..c8d282d18af --- /dev/null +++ b/src/librustc/ty/cast.rs @@ -0,0 +1,76 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Helpers for handling cast expressions, used in both +// typeck and trans. + +use ty::{self, Ty}; + +use syntax::ast; + +/// Types that are represented as ints. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum IntTy { + U(ast::UintTy), + I, + CEnum, + Bool, + Char +} + +// Valid types for the result of a non-coercion cast +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum CastTy<'tcx> { + /// Various types that are represented as ints and handled mostly + /// in the same way, merged for easier matching. + Int(IntTy), + /// Floating-Point types + Float, + /// Function Pointers + FnPtr, + /// Raw pointers + Ptr(&'tcx ty::TypeAndMut<'tcx>), + /// References + RPtr(&'tcx ty::TypeAndMut<'tcx>), +} + +/// Cast Kind. See RFC 401 (or librustc_typeck/check/cast.rs) +#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)] +pub enum CastKind { + CoercionCast, + PtrPtrCast, + PtrAddrCast, + AddrPtrCast, + NumericCast, + EnumCast, + PrimIntCast, + U8CharCast, + ArrayPtrCast, + FnPtrPtrCast, + FnPtrAddrCast +} + +impl<'tcx> CastTy<'tcx> { + pub fn from_ty(t: Ty<'tcx>) -> Option> { + match t.sty { + ty::TyBool => Some(CastTy::Int(IntTy::Bool)), + ty::TyChar => Some(CastTy::Int(IntTy::Char)), + ty::TyInt(_) => Some(CastTy::Int(IntTy::I)), + ty::TyUint(u) => Some(CastTy::Int(IntTy::U(u))), + ty::TyFloat(_) => Some(CastTy::Float), + ty::TyEnum(d,_) if d.is_payloadfree() => + Some(CastTy::Int(IntTy::CEnum)), + ty::TyRawPtr(ref mt) => Some(CastTy::Ptr(mt)), + ty::TyRef(_, ref mt) => Some(CastTy::RPtr(mt)), + ty::TyFnPtr(..) => Some(CastTy::FnPtr), + _ => None, + } + } +} diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs new file mode 100644 index 00000000000..cb84b198222 --- /dev/null +++ b/src/librustc/ty/contents.rs @@ -0,0 +1,267 @@ +// Copyright 2012-2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use middle::def_id::{DefId}; +use ty::{self, Ty, TyCtxt}; +use util::common::MemoizationMap; +use util::nodemap::FnvHashMap; + +use std::fmt; +use std::ops; + +use syntax::ast; + +/// Type contents is how the type checker reasons about kinds. +/// They track what kinds of things are found within a type. You can +/// think of them as kind of an "anti-kind". They track the kinds of values +/// and thinks that are contained in types. Having a larger contents for +/// a type tends to rule that type *out* from various kinds. For example, +/// a type that contains a reference is not sendable. +/// +/// The reason we compute type contents and not kinds is that it is +/// easier for me (nmatsakis) to think about what is contained within +/// a type than to think about what is *not* contained within a type. +#[derive(Clone, Copy)] +pub struct TypeContents { + pub bits: u64 +} + +macro_rules! def_type_content_sets { + (mod $mname:ident { $($name:ident = $bits:expr),+ }) => { + #[allow(non_snake_case)] + mod $mname { + use super::TypeContents; + $( + #[allow(non_upper_case_globals)] + pub const $name: TypeContents = TypeContents { bits: $bits }; + )+ + } + } +} + +def_type_content_sets! { + mod TC { + None = 0b0000_0000__0000_0000__0000, + + // Things that are interior to the value (first nibble): + InteriorUnsafe = 0b0000_0000__0000_0000__0010, + InteriorParam = 0b0000_0000__0000_0000__0100, + // InteriorAll = 0b00000000__00000000__1111, + + // Things that are owned by the value (second and third nibbles): + OwnsOwned = 0b0000_0000__0000_0001__0000, + OwnsDtor = 0b0000_0000__0000_0010__0000, + OwnsAll = 0b0000_0000__1111_1111__0000, + + // Things that mean drop glue is necessary + NeedsDrop = 0b0000_0000__0000_0111__0000, + + // All bits + All = 0b1111_1111__1111_1111__1111 + } +} + +impl TypeContents { + pub fn when(&self, cond: bool) -> TypeContents { + if cond {*self} else {TC::None} + } + + pub fn intersects(&self, tc: TypeContents) -> bool { + (self.bits & tc.bits) != 0 + } + + pub fn owns_owned(&self) -> bool { + self.intersects(TC::OwnsOwned) + } + + pub fn interior_param(&self) -> bool { + self.intersects(TC::InteriorParam) + } + + pub fn interior_unsafe(&self) -> bool { + self.intersects(TC::InteriorUnsafe) + } + + pub fn needs_drop(&self, _: &TyCtxt) -> bool { + self.intersects(TC::NeedsDrop) + } + + /// Includes only those bits that still apply when indirected through a `Box` pointer + pub fn owned_pointer(&self) -> TypeContents { + TC::OwnsOwned | (*self & TC::OwnsAll) + } + + pub fn union(v: &[T], mut f: F) -> TypeContents where + F: FnMut(&T) -> TypeContents, + { + v.iter().fold(TC::None, |tc, ty| tc | f(ty)) + } + + pub fn has_dtor(&self) -> bool { + self.intersects(TC::OwnsDtor) + } +} + +impl ops::BitOr for TypeContents { + type Output = TypeContents; + + fn bitor(self, other: TypeContents) -> TypeContents { + TypeContents {bits: self.bits | other.bits} + } +} + +impl ops::BitAnd for TypeContents { + type Output = TypeContents; + + fn bitand(self, other: TypeContents) -> TypeContents { + TypeContents {bits: self.bits & other.bits} + } +} + +impl ops::Sub for TypeContents { + type Output = TypeContents; + + fn sub(self, other: TypeContents) -> TypeContents { + TypeContents {bits: self.bits & !other.bits} + } +} + +impl fmt::Debug for TypeContents { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "TypeContents({:b})", self.bits) + } +} + +impl<'tcx> ty::TyS<'tcx> { + pub fn type_contents(&'tcx self, cx: &TyCtxt<'tcx>) -> TypeContents { + return cx.tc_cache.memoize(self, || tc_ty(cx, self, &mut FnvHashMap())); + + fn tc_ty<'tcx>(cx: &TyCtxt<'tcx>, + ty: Ty<'tcx>, + cache: &mut FnvHashMap, TypeContents>) -> TypeContents + { + // Subtle: Note that we are *not* using cx.tc_cache here but rather a + // private cache for this walk. This is needed in the case of cyclic + // types like: + // + // struct List { next: Box>, ... } + // + // When computing the type contents of such a type, we wind up deeply + // recursing as we go. So when we encounter the recursive reference + // to List, we temporarily use TC::None as its contents. Later we'll + // patch up the cache with the correct value, once we've computed it + // (this is basically a co-inductive process, if that helps). So in + // the end we'll compute TC::OwnsOwned, in this case. + // + // The problem is, as we are doing the computation, we will also + // compute an *intermediate* contents for, e.g., Option of + // TC::None. This is ok during the computation of List itself, but if + // we stored this intermediate value into cx.tc_cache, then later + // requests for the contents of Option would also yield TC::None + // which is incorrect. This value was computed based on the crutch + // value for the type contents of list. The correct value is + // TC::OwnsOwned. This manifested as issue #4821. + match cache.get(&ty) { + Some(tc) => { return *tc; } + None => {} + } + match cx.tc_cache.borrow().get(&ty) { // Must check both caches! + Some(tc) => { return *tc; } + None => {} + } + cache.insert(ty, TC::None); + + let result = match ty.sty { + // usize and isize are ffi-unsafe + ty::TyUint(ast::UintTy::Us) | ty::TyInt(ast::IntTy::Is) => { + TC::None + } + + // Scalar and unique types are sendable, and durable + ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) | + ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | + ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar => { + TC::None + } + + ty::TyBox(typ) => { + tc_ty(cx, typ, cache).owned_pointer() + } + + ty::TyTrait(_) => { + TC::All - TC::InteriorParam + } + + ty::TyRawPtr(_) => { + TC::None + } + + ty::TyRef(_, _) => { + TC::None + } + + ty::TyArray(ty, _) => { + tc_ty(cx, ty, cache) + } + + ty::TySlice(ty) => { + tc_ty(cx, ty, cache) + } + ty::TyStr => TC::None, + + ty::TyClosure(_, ref substs) => { + TypeContents::union(&substs.upvar_tys, |ty| tc_ty(cx, &ty, cache)) + } + + ty::TyTuple(ref tys) => { + TypeContents::union(&tys[..], + |ty| tc_ty(cx, *ty, cache)) + } + + ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { + let mut res = + TypeContents::union(&def.variants, |v| { + TypeContents::union(&v.fields, |f| { + tc_ty(cx, f.ty(cx, substs), cache) + }) + }); + + if def.has_dtor() { + res = res | TC::OwnsDtor; + } + + apply_lang_items(cx, def.did, res) + } + + ty::TyProjection(..) | + ty::TyParam(_) => { + TC::All + } + + ty::TyInfer(_) | + ty::TyError => { + cx.sess.bug("asked to compute contents of error type"); + } + }; + + cache.insert(ty, result); + result + } + + fn apply_lang_items(cx: &TyCtxt, did: DefId, tc: TypeContents) + -> TypeContents { + if Some(did) == cx.lang_items.unsafe_cell_type() { + tc | TC::InteriorUnsafe + } else { + tc + } + } + } +} diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs new file mode 100644 index 00000000000..49e9eda5651 --- /dev/null +++ b/src/librustc/ty/context.rs @@ -0,0 +1,1081 @@ +// Copyright 2012-2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! type context book-keeping + +use dep_graph::{DepGraph, DepTrackingMap}; +use front::map as ast_map; +use session::Session; +use lint; +use middle; +use middle::cstore::{CrateStore, LOCAL_CRATE}; +use middle::def::DefMap; +use middle::def_id::DefId; +use middle::free_region::FreeRegionMap; +use middle::region::RegionMaps; +use middle::resolve_lifetime; +use middle::stability; +use ty::subst::{self, Subst, Substs}; +use traits; +use ty::{self, TraitRef, Ty, TypeAndMut}; +use ty::{TyS, TypeVariants}; +use ty::{AdtDef, ClosureSubsts, ExistentialBounds, Region}; +use ty::{FreevarMap}; +use ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, TraitTy}; +use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid}; +use ty::TypeVariants::*; +use ty::maps; +use util::common::MemoizationMap; +use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet}; +use util::nodemap::FnvHashMap; + +use arena::TypedArena; +use std::borrow::Borrow; +use std::cell::{Cell, RefCell, Ref}; +use std::hash::{Hash, Hasher}; +use std::rc::Rc; +use syntax::ast::{self, Name, NodeId}; +use syntax::attr; +use syntax::parse::token::{self, special_idents}; + +use rustc_front::hir; + +/// Internal storage +pub struct CtxtArenas<'tcx> { + // internings + type_: TypedArena>, + substs: TypedArena>, + bare_fn: TypedArena>, + region: TypedArena, + stability: TypedArena, + + // references + trait_defs: TypedArena>, + adt_defs: TypedArena>, +} + +impl<'tcx> CtxtArenas<'tcx> { + pub fn new() -> CtxtArenas<'tcx> { + CtxtArenas { + type_: TypedArena::new(), + substs: TypedArena::new(), + bare_fn: TypedArena::new(), + region: TypedArena::new(), + stability: TypedArena::new(), + + trait_defs: TypedArena::new(), + adt_defs: TypedArena::new() + } + } +} + +pub struct CommonTypes<'tcx> { + pub bool: Ty<'tcx>, + pub char: Ty<'tcx>, + pub isize: Ty<'tcx>, + pub i8: Ty<'tcx>, + pub i16: Ty<'tcx>, + pub i32: Ty<'tcx>, + pub i64: Ty<'tcx>, + pub usize: Ty<'tcx>, + pub u8: Ty<'tcx>, + pub u16: Ty<'tcx>, + pub u32: Ty<'tcx>, + pub u64: Ty<'tcx>, + pub f32: Ty<'tcx>, + pub f64: Ty<'tcx>, + pub err: Ty<'tcx>, +} + +pub struct Tables<'tcx> { + /// Stores the types for various nodes in the AST. Note that this table + /// is not guaranteed to be populated until after typeck. See + /// typeck::check::fn_ctxt for details. + pub node_types: NodeMap>, + + /// Stores the type parameters which were substituted to obtain the type + /// of this node. This only applies to nodes that refer to entities + /// parameterized by type parameters, such as generic fns, types, or + /// other items. + pub item_substs: NodeMap>, + + pub adjustments: NodeMap>, + + pub method_map: ty::MethodMap<'tcx>, + + /// Borrows + pub upvar_capture_map: ty::UpvarCaptureMap, + + /// Records the type of each closure. The def ID is the ID of the + /// expression defining the closure. + pub closure_tys: DefIdMap>, + + /// Records the type of each closure. The def ID is the ID of the + /// expression defining the closure. + pub closure_kinds: DefIdMap, + + /// For each fn, records the "liberated" types of its arguments + /// and return type. Liberated means that all bound regions + /// (including late-bound regions) are replaced with free + /// equivalents. This table is not used in trans (since regions + /// are erased there) and hence is not serialized to metadata. + pub liberated_fn_sigs: NodeMap>, + + /// For each FRU expression, record the normalized types of the fields + /// of the struct - this is needed because it is non-trivial to + /// normalize while preserving regions. This table is used only in + /// MIR construction and hence is not serialized to metadata. + pub fru_field_types: NodeMap>> +} + +impl<'tcx> Tables<'tcx> { + pub fn empty() -> Tables<'tcx> { + Tables { + node_types: FnvHashMap(), + item_substs: NodeMap(), + adjustments: NodeMap(), + method_map: FnvHashMap(), + upvar_capture_map: FnvHashMap(), + closure_tys: DefIdMap(), + closure_kinds: DefIdMap(), + liberated_fn_sigs: NodeMap(), + fru_field_types: NodeMap() + } + } + + pub fn closure_kind(this: &RefCell, + tcx: &TyCtxt<'tcx>, + def_id: DefId) + -> ty::ClosureKind { + // If this is a local def-id, it should be inserted into the + // tables by typeck; else, it will be retreived from + // the external crate metadata. + if let Some(&kind) = this.borrow().closure_kinds.get(&def_id) { + return kind; + } + + let kind = tcx.sess.cstore.closure_kind(tcx, def_id); + this.borrow_mut().closure_kinds.insert(def_id, kind); + kind + } + + pub fn closure_type(this: &RefCell, + tcx: &TyCtxt<'tcx>, + def_id: DefId, + substs: &ClosureSubsts<'tcx>) + -> ty::ClosureTy<'tcx> + { + // If this is a local def-id, it should be inserted into the + // tables by typeck; else, it will be retreived from + // the external crate metadata. + if let Some(ty) = this.borrow().closure_tys.get(&def_id) { + return ty.subst(tcx, &substs.func_substs); + } + + let ty = tcx.sess.cstore.closure_ty(tcx, def_id); + this.borrow_mut().closure_tys.insert(def_id, ty.clone()); + ty.subst(tcx, &substs.func_substs) + } +} + +impl<'tcx> CommonTypes<'tcx> { + fn new(arena: &'tcx TypedArena>, + interner: &RefCell, Ty<'tcx>>>) + -> CommonTypes<'tcx> + { + let mk = |sty| TyCtxt::intern_ty(arena, interner, sty); + CommonTypes { + bool: mk(TyBool), + char: mk(TyChar), + err: mk(TyError), + isize: mk(TyInt(ast::IntTy::Is)), + i8: mk(TyInt(ast::IntTy::I8)), + i16: mk(TyInt(ast::IntTy::I16)), + i32: mk(TyInt(ast::IntTy::I32)), + i64: mk(TyInt(ast::IntTy::I64)), + usize: mk(TyUint(ast::UintTy::Us)), + u8: mk(TyUint(ast::UintTy::U8)), + u16: mk(TyUint(ast::UintTy::U16)), + u32: mk(TyUint(ast::UintTy::U32)), + u64: mk(TyUint(ast::UintTy::U64)), + f32: mk(TyFloat(ast::FloatTy::F32)), + f64: mk(TyFloat(ast::FloatTy::F64)), + } + } +} + +/// The data structure to keep track of all the information that typechecker +/// generates so that so that it can be reused and doesn't have to be redone +/// later on. +pub struct TyCtxt<'tcx> { + /// The arenas that types etc are allocated from. + arenas: &'tcx CtxtArenas<'tcx>, + + /// Specifically use a speedy hash algorithm for this hash map, it's used + /// quite often. + // FIXME(eddyb) use a FnvHashSet> when equivalent keys can + // queried from a HashSet. + interner: RefCell, Ty<'tcx>>>, + + // FIXME as above, use a hashset if equivalent elements can be queried. + substs_interner: RefCell, &'tcx Substs<'tcx>>>, + bare_fn_interner: RefCell, &'tcx BareFnTy<'tcx>>>, + region_interner: RefCell>, + stability_interner: RefCell>, + + pub dep_graph: DepGraph, + + /// Common types, pre-interned for your convenience. + pub types: CommonTypes<'tcx>, + + pub sess: &'tcx Session, + pub def_map: RefCell, + + pub named_region_map: resolve_lifetime::NamedRegionMap, + + pub region_maps: RegionMaps, + + // For each fn declared in the local crate, type check stores the + // free-region relationships that were deduced from its where + // clauses and parameter types. These are then read-again by + // borrowck. (They are not used during trans, and hence are not + // serialized or needed for cross-crate fns.) + free_region_maps: RefCell>, + // FIXME: jroesch make this a refcell + + pub tables: RefCell>, + + /// Maps from a trait item to the trait item "descriptor" + pub impl_or_trait_items: RefCell>>, + + /// Maps from a trait def-id to a list of the def-ids of its trait items + pub trait_item_def_ids: RefCell>>, + + /// A cache for the trait_items() routine; note that the routine + /// itself pushes the `TraitItems` dependency node. + trait_items_cache: RefCell>>, + + pub impl_trait_refs: RefCell>>, + pub trait_defs: RefCell>>, + pub adt_defs: RefCell>>, + + /// Maps from the def-id of an item (trait/struct/enum/fn) to its + /// associated predicates. + pub predicates: RefCell>>, + + /// Maps from the def-id of a trait to the list of + /// super-predicates. This is a subset of the full list of + /// predicates. We store these in a separate map because we must + /// evaluate them even during type conversion, often before the + /// full predicates are available (note that supertraits have + /// additional acyclicity requirements). + pub super_predicates: RefCell>>, + + pub map: ast_map::Map<'tcx>, + + // Records the free variables refrenced by every closure + // expression. Do not track deps for this, just recompute it from + // scratch every time. + pub freevars: RefCell, + + // Records the type of every item. + pub tcache: RefCell>>, + + // Internal cache for metadata decoding. No need to track deps on this. + pub rcache: RefCell>>, + + // Cache for the type-contents routine. FIXME -- track deps? + pub tc_cache: RefCell, ty::contents::TypeContents>>, + + // Cache for various types within a method body and so forth. + // + // FIXME this should be made local to typeck, but it is currently used by one lint + pub ast_ty_to_ty_cache: RefCell>>, + + // FIXME no dep tracking, but we should be able to remove this + pub ty_param_defs: RefCell>>, + + // FIXME dep tracking -- should be harmless enough + pub normalized_cache: RefCell, Ty<'tcx>>>, + + pub lang_items: middle::lang_items::LanguageItems, + + /// Maps from def-id of a type or region parameter to its + /// (inferred) variance. + pub item_variance_map: RefCell>>, + + /// True if the variance has been computed yet; false otherwise. + pub variance_computed: Cell, + + /// Maps a DefId of a type to a list of its inherent impls. + /// Contains implementations of methods that are inherent to a type. + /// Methods in these implementations don't need to be exported. + pub inherent_impls: RefCell>>, + + /// Maps a DefId of an impl to a list of its items. + /// Note that this contains all of the impls that we know about, + /// including ones in other crates. It's not clear that this is the best + /// way to do it. + pub impl_items: RefCell>>, + + /// Set of used unsafe nodes (functions or blocks). Unsafe nodes not + /// present in this set can be warned about. + pub used_unsafe: RefCell, + + /// Set of nodes which mark locals as mutable which end up getting used at + /// some point. Local variable definitions not in this set can be warned + /// about. + pub used_mut_nodes: RefCell, + + /// The set of external nominal types whose implementations have been read. + /// This is used for lazy resolution of methods. + pub populated_external_types: RefCell, + + /// The set of external primitive types whose implementations have been read. + /// FIXME(arielb1): why is this separate from populated_external_types? + pub populated_external_primitive_impls: RefCell, + + /// Cache used by const_eval when decoding external constants. + /// Contains `None` when the constant has been fetched but doesn't exist. + /// Constains `Some(expr_id, type)` otherwise. + /// `type` is `None` in case it's not a primitive type + pub extern_const_statics: RefCell>)>>>, + /// Cache used by const_eval when decoding extern const fns + pub extern_const_fns: RefCell>, + + pub node_lint_levels: RefCell>, + + /// The types that must be asserted to be the same size for `transmute` + /// to be valid. We gather up these restrictions in the intrinsicck pass + /// and check them in trans. + pub transmute_restrictions: RefCell>>, + + /// Maps any item's def-id to its stability index. + pub stability: RefCell>, + + /// Caches the results of trait selection. This cache is used + /// for things that do not have to do with the parameters in scope. + pub selection_cache: traits::SelectionCache<'tcx>, + + /// Caches the results of trait evaluation. This cache is used + /// for things that do not have to do with the parameters in scope. + /// Merge this with `selection_cache`? + pub evaluation_cache: traits::EvaluationCache<'tcx>, + + /// A set of predicates that have been fulfilled *somewhere*. + /// This is used to avoid duplicate work. Predicates are only + /// added to this set when they mention only "global" names + /// (i.e., no type or lifetime parameters). + pub fulfilled_predicates: RefCell>, + + /// Caches the representation hints for struct definitions. + repr_hint_cache: RefCell>>, + + /// Maps Expr NodeId's to their constant qualification. + pub const_qualif_map: RefCell>, + + /// Caches CoerceUnsized kinds for impls on custom types. + pub custom_coerce_unsized_kinds: RefCell>, + + /// Maps a cast expression to its kind. This is keyed on the + /// *from* expression of the cast, not the cast itself. + pub cast_kinds: RefCell>, + + /// Maps Fn items to a collection of fragment infos. + /// + /// The main goal is to identify data (each of which may be moved + /// or assigned) whose subparts are not moved nor assigned + /// (i.e. their state is *unfragmented*) and corresponding ast + /// nodes where the path to that data is moved or assigned. + /// + /// In the long term, unfragmented values will have their + /// destructor entirely driven by a single stack-local drop-flag, + /// and their parents, the collections of the unfragmented values + /// (or more simply, "fragmented values"), are mapped to the + /// corresponding collections of stack-local drop-flags. + /// + /// (However, in the short term that is not the case; e.g. some + /// unfragmented paths still need to be zeroed, namely when they + /// reference parent data from an outer scope that was not + /// entirely moved, and therefore that needs to be zeroed so that + /// we do not get double-drop when we hit the end of the parent + /// scope.) + /// + /// Also: currently the table solely holds keys for node-ids of + /// unfragmented values (see `FragmentInfo` enum definition), but + /// longer-term we will need to also store mappings from + /// fragmented data to the set of unfragmented pieces that + /// constitute it. + pub fragment_infos: RefCell>>, + + /// The definite name of the current crate after taking into account + /// attributes, commandline parameters, etc. + pub crate_name: token::InternedString, +} + +impl<'tcx> TyCtxt<'tcx> { + pub fn crate_name(&self, cnum: ast::CrateNum) -> token::InternedString { + if cnum == LOCAL_CRATE { + self.crate_name.clone() + } else { + self.sess.cstore.crate_name(cnum) + } + } + + pub fn crate_disambiguator(&self, cnum: ast::CrateNum) -> token::InternedString { + if cnum == LOCAL_CRATE { + self.sess.crate_disambiguator.get().as_str() + } else { + self.sess.cstore.crate_name(cnum) + } + } + + pub fn type_parameter_def(&self, + node_id: NodeId) + -> ty::TypeParameterDef<'tcx> + { + self.ty_param_defs.borrow().get(&node_id).unwrap().clone() + } + + pub fn node_types(&self) -> Ref>> { + fn projection<'a, 'tcx>(tables: &'a Tables<'tcx>) -> &'a NodeMap> { + &tables.node_types + } + + Ref::map(self.tables.borrow(), projection) + } + + pub fn node_type_insert(&self, id: NodeId, ty: Ty<'tcx>) { + self.tables.borrow_mut().node_types.insert(id, ty); + } + + pub fn intern_trait_def(&self, def: ty::TraitDef<'tcx>) + -> &'tcx ty::TraitDef<'tcx> { + let did = def.trait_ref.def_id; + let interned = self.arenas.trait_defs.alloc(def); + if let Some(prev) = self.trait_defs.borrow_mut().insert(did, interned) { + self.sess.bug(&format!("Tried to overwrite interned TraitDef: {:?}", + prev)) + } + interned + } + + pub fn alloc_trait_def(&self, def: ty::TraitDef<'tcx>) + -> &'tcx ty::TraitDef<'tcx> { + self.arenas.trait_defs.alloc(def) + } + + pub fn intern_adt_def(&self, + did: DefId, + kind: ty::AdtKind, + variants: Vec>) + -> ty::AdtDefMaster<'tcx> { + let def = ty::AdtDefData::new(self, did, kind, variants); + let interned = self.arenas.adt_defs.alloc(def); + // this will need a transmute when reverse-variance is removed + if let Some(prev) = self.adt_defs.borrow_mut().insert(did, interned) { + self.sess.bug(&format!("Tried to overwrite interned AdtDef: {:?}", + prev)) + } + interned + } + + pub fn intern_stability(&self, stab: attr::Stability) -> &'tcx attr::Stability { + if let Some(st) = self.stability_interner.borrow().get(&stab) { + return st; + } + + let interned = self.arenas.stability.alloc(stab); + if let Some(prev) = self.stability_interner + .borrow_mut() + .insert(interned, interned) { + self.sess.bug(&format!("Tried to overwrite interned Stability: {:?}", + prev)) + } + interned + } + + pub fn store_free_region_map(&self, id: NodeId, map: FreeRegionMap) { + if self.free_region_maps.borrow_mut().insert(id, map).is_some() { + self.sess.bug(&format!("Tried to overwrite interned FreeRegionMap for NodeId {:?}", + id)) + } + } + + pub fn free_region_map(&self, id: NodeId) -> FreeRegionMap { + self.free_region_maps.borrow()[&id].clone() + } + + pub fn lift>(&self, value: &T) -> Option { + value.lift_to_tcx(self) + } + + /// Create a type context and call the closure with a `&TyCtxt` reference + /// to the context. The closure enforces that the type context and any interned + /// value (types, substs, etc.) can only be used while `ty::tls` has a valid + /// reference to the context, to allow formatting values that need it. + pub fn create_and_enter(s: &'tcx Session, + arenas: &'tcx CtxtArenas<'tcx>, + def_map: RefCell, + named_region_map: resolve_lifetime::NamedRegionMap, + map: ast_map::Map<'tcx>, + freevars: FreevarMap, + region_maps: RegionMaps, + lang_items: middle::lang_items::LanguageItems, + stability: stability::Index<'tcx>, + crate_name: &str, + f: F) -> R + where F: FnOnce(&TyCtxt<'tcx>) -> R + { + let interner = RefCell::new(FnvHashMap()); + let common_types = CommonTypes::new(&arenas.type_, &interner); + let dep_graph = map.dep_graph.clone(); + let fulfilled_predicates = traits::GlobalFulfilledPredicates::new(dep_graph.clone()); + tls::enter(TyCtxt { + arenas: arenas, + interner: interner, + substs_interner: RefCell::new(FnvHashMap()), + bare_fn_interner: RefCell::new(FnvHashMap()), + region_interner: RefCell::new(FnvHashMap()), + stability_interner: RefCell::new(FnvHashMap()), + dep_graph: dep_graph.clone(), + types: common_types, + named_region_map: named_region_map, + region_maps: region_maps, + free_region_maps: RefCell::new(FnvHashMap()), + item_variance_map: RefCell::new(DepTrackingMap::new(dep_graph.clone())), + variance_computed: Cell::new(false), + sess: s, + def_map: def_map, + tables: RefCell::new(Tables::empty()), + impl_trait_refs: RefCell::new(DepTrackingMap::new(dep_graph.clone())), + trait_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())), + adt_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())), + predicates: RefCell::new(DepTrackingMap::new(dep_graph.clone())), + super_predicates: RefCell::new(DepTrackingMap::new(dep_graph.clone())), + fulfilled_predicates: RefCell::new(fulfilled_predicates), + map: map, + freevars: RefCell::new(freevars), + tcache: RefCell::new(DepTrackingMap::new(dep_graph.clone())), + rcache: RefCell::new(FnvHashMap()), + tc_cache: RefCell::new(FnvHashMap()), + ast_ty_to_ty_cache: RefCell::new(NodeMap()), + impl_or_trait_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())), + trait_item_def_ids: RefCell::new(DepTrackingMap::new(dep_graph.clone())), + trait_items_cache: RefCell::new(DepTrackingMap::new(dep_graph.clone())), + ty_param_defs: RefCell::new(NodeMap()), + normalized_cache: RefCell::new(FnvHashMap()), + lang_items: lang_items, + inherent_impls: RefCell::new(DepTrackingMap::new(dep_graph.clone())), + impl_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())), + used_unsafe: RefCell::new(NodeSet()), + used_mut_nodes: RefCell::new(NodeSet()), + populated_external_types: RefCell::new(DefIdSet()), + populated_external_primitive_impls: RefCell::new(DefIdSet()), + extern_const_statics: RefCell::new(DefIdMap()), + extern_const_fns: RefCell::new(DefIdMap()), + node_lint_levels: RefCell::new(FnvHashMap()), + transmute_restrictions: RefCell::new(Vec::new()), + stability: RefCell::new(stability), + selection_cache: traits::SelectionCache::new(), + evaluation_cache: traits::EvaluationCache::new(), + repr_hint_cache: RefCell::new(DepTrackingMap::new(dep_graph.clone())), + const_qualif_map: RefCell::new(NodeMap()), + custom_coerce_unsized_kinds: RefCell::new(DefIdMap()), + cast_kinds: RefCell::new(NodeMap()), + fragment_infos: RefCell::new(DefIdMap()), + crate_name: token::intern_and_get_ident(crate_name), + }, f) + } +} + +/// A trait implemented for all X<'a> types which can be safely and +/// efficiently converted to X<'tcx> as long as they are part of the +/// provided TyCtxt<'tcx>. +/// This can be done, for example, for Ty<'tcx> or &'tcx Substs<'tcx> +/// by looking them up in their respective interners. +/// None is returned if the value or one of the components is not part +/// of the provided context. +/// For Ty, None can be returned if either the type interner doesn't +/// contain the TypeVariants key or if the address of the interned +/// pointer differs. The latter case is possible if a primitive type, +/// e.g. `()` or `u8`, was interned in a different context. +pub trait Lift<'tcx> { + type Lifted; + fn lift_to_tcx(&self, tcx: &TyCtxt<'tcx>) -> Option; +} + +impl<'a, 'tcx> Lift<'tcx> for Ty<'a> { + type Lifted = Ty<'tcx>; + fn lift_to_tcx(&self, tcx: &TyCtxt<'tcx>) -> Option> { + if let Some(&ty) = tcx.interner.borrow().get(&self.sty) { + if *self as *const _ == ty as *const _ { + return Some(ty); + } + } + None + } +} + +impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> { + type Lifted = &'tcx Substs<'tcx>; + fn lift_to_tcx(&self, tcx: &TyCtxt<'tcx>) -> Option<&'tcx Substs<'tcx>> { + if let Some(&substs) = tcx.substs_interner.borrow().get(*self) { + if *self as *const _ == substs as *const _ { + return Some(substs); + } + } + None + } +} + + +pub mod tls { + use ty::TyCtxt; + + use std::cell::Cell; + use std::fmt; + use syntax::codemap; + + /// Marker type used for the scoped TLS slot. + /// The type context cannot be used directly because the scoped TLS + /// in libstd doesn't allow types generic over lifetimes. + struct ThreadLocalTyCx; + + thread_local! { + static TLS_TCX: Cell> = Cell::new(None) + } + + fn span_debug(span: codemap::Span, f: &mut fmt::Formatter) -> fmt::Result { + with(|tcx| { + write!(f, "{}", tcx.sess.codemap().span_to_string(span)) + }) + } + + pub fn enter<'tcx, F: FnOnce(&TyCtxt<'tcx>) -> R, R>(tcx: TyCtxt<'tcx>, f: F) -> R { + codemap::SPAN_DEBUG.with(|span_dbg| { + let original_span_debug = span_dbg.get(); + span_dbg.set(span_debug); + let tls_ptr = &tcx as *const _ as *const ThreadLocalTyCx; + let result = TLS_TCX.with(|tls| { + let prev = tls.get(); + tls.set(Some(tls_ptr)); + let ret = f(&tcx); + tls.set(prev); + ret + }); + span_dbg.set(original_span_debug); + result + }) + } + + pub fn with R, R>(f: F) -> R { + TLS_TCX.with(|tcx| { + let tcx = tcx.get().unwrap(); + f(unsafe { &*(tcx as *const TyCtxt) }) + }) + } + + pub fn with_opt) -> R, R>(f: F) -> R { + if TLS_TCX.with(|tcx| tcx.get().is_some()) { + with(|v| f(Some(v))) + } else { + f(None) + } + } +} + +macro_rules! sty_debug_print { + ($ctxt: expr, $($variant: ident),*) => {{ + // curious inner module to allow variant names to be used as + // variable names. + #[allow(non_snake_case)] + mod inner { + use ty::{self, TyCtxt}; + #[derive(Copy, Clone)] + struct DebugStat { + total: usize, + region_infer: usize, + ty_infer: usize, + both_infer: usize, + } + + pub fn go(tcx: &TyCtxt) { + let mut total = DebugStat { + total: 0, + region_infer: 0, ty_infer: 0, both_infer: 0, + }; + $(let mut $variant = total;)* + + + for (_, t) in tcx.interner.borrow().iter() { + let variant = match t.sty { + ty::TyBool | ty::TyChar | ty::TyInt(..) | ty::TyUint(..) | + ty::TyFloat(..) | ty::TyStr => continue, + ty::TyError => /* unimportant */ continue, + $(ty::$variant(..) => &mut $variant,)* + }; + let region = t.flags.get().intersects(ty::TypeFlags::HAS_RE_INFER); + let ty = t.flags.get().intersects(ty::TypeFlags::HAS_TY_INFER); + + variant.total += 1; + total.total += 1; + if region { total.region_infer += 1; variant.region_infer += 1 } + if ty { total.ty_infer += 1; variant.ty_infer += 1 } + if region && ty { total.both_infer += 1; variant.both_infer += 1 } + } + println!("Ty interner total ty region both"); + $(println!(" {:18}: {uses:6} {usespc:4.1}%, \ +{ty:4.1}% {region:5.1}% {both:4.1}%", + stringify!($variant), + uses = $variant.total, + usespc = $variant.total as f64 * 100.0 / total.total as f64, + ty = $variant.ty_infer as f64 * 100.0 / total.total as f64, + region = $variant.region_infer as f64 * 100.0 / total.total as f64, + both = $variant.both_infer as f64 * 100.0 / total.total as f64); + )* + println!(" total {uses:6} \ +{ty:4.1}% {region:5.1}% {both:4.1}%", + uses = total.total, + ty = total.ty_infer as f64 * 100.0 / total.total as f64, + region = total.region_infer as f64 * 100.0 / total.total as f64, + both = total.both_infer as f64 * 100.0 / total.total as f64) + } + } + + inner::go($ctxt) + }} +} + +impl<'tcx> TyCtxt<'tcx> { + pub fn print_debug_stats(&self) { + sty_debug_print!( + self, + TyEnum, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, + TyTrait, TyStruct, TyClosure, TyTuple, TyParam, TyInfer, TyProjection); + + println!("Substs interner: #{}", self.substs_interner.borrow().len()); + println!("BareFnTy interner: #{}", self.bare_fn_interner.borrow().len()); + println!("Region interner: #{}", self.region_interner.borrow().len()); + println!("Stability interner: #{}", self.stability_interner.borrow().len()); + } +} + + +/// An entry in the type interner. +pub struct InternedTy<'tcx> { + ty: Ty<'tcx> +} + +// NB: An InternedTy compares and hashes as a sty. +impl<'tcx> PartialEq for InternedTy<'tcx> { + fn eq(&self, other: &InternedTy<'tcx>) -> bool { + self.ty.sty == other.ty.sty + } +} + +impl<'tcx> Eq for InternedTy<'tcx> {} + +impl<'tcx> Hash for InternedTy<'tcx> { + fn hash(&self, s: &mut H) { + self.ty.sty.hash(s) + } +} + +impl<'tcx> Borrow> for InternedTy<'tcx> { + fn borrow<'a>(&'a self) -> &'a TypeVariants<'tcx> { + &self.ty.sty + } +} + +fn bound_list_is_sorted(bounds: &[ty::PolyProjectionPredicate]) -> bool { + bounds.is_empty() || + bounds[1..].iter().enumerate().all( + |(index, bound)| bounds[index].sort_key() <= bound.sort_key()) +} + +impl<'tcx> TyCtxt<'tcx> { + // Type constructors + pub fn mk_substs(&self, substs: Substs<'tcx>) -> &'tcx Substs<'tcx> { + if let Some(substs) = self.substs_interner.borrow().get(&substs) { + return *substs; + } + + let substs = self.arenas.substs.alloc(substs); + self.substs_interner.borrow_mut().insert(substs, substs); + substs + } + + /// Create an unsafe fn ty based on a safe fn ty. + pub fn safe_to_unsafe_fn_ty(&self, bare_fn: &BareFnTy<'tcx>) -> Ty<'tcx> { + assert_eq!(bare_fn.unsafety, hir::Unsafety::Normal); + self.mk_fn_ptr(ty::BareFnTy { + unsafety: hir::Unsafety::Unsafe, + abi: bare_fn.abi, + sig: bare_fn.sig.clone() + }) + } + + pub fn mk_bare_fn(&self, bare_fn: BareFnTy<'tcx>) -> &'tcx BareFnTy<'tcx> { + if let Some(bare_fn) = self.bare_fn_interner.borrow().get(&bare_fn) { + return *bare_fn; + } + + let bare_fn = self.arenas.bare_fn.alloc(bare_fn); + self.bare_fn_interner.borrow_mut().insert(bare_fn, bare_fn); + bare_fn + } + + pub fn mk_region(&self, region: Region) -> &'tcx Region { + if let Some(region) = self.region_interner.borrow().get(®ion) { + return *region; + } + + let region = self.arenas.region.alloc(region); + self.region_interner.borrow_mut().insert(region, region); + region + } + + fn intern_ty(type_arena: &'tcx TypedArena>, + interner: &RefCell, Ty<'tcx>>>, + st: TypeVariants<'tcx>) + -> Ty<'tcx> { + let ty: Ty /* don't be &mut TyS */ = { + let mut interner = interner.borrow_mut(); + match interner.get(&st) { + Some(ty) => return *ty, + _ => () + } + + let flags = super::flags::FlagComputation::for_sty(&st); + + let ty = match () { + () => type_arena.alloc(TyS { sty: st, + flags: Cell::new(flags.flags), + region_depth: flags.depth, }), + }; + + interner.insert(InternedTy { ty: ty }, ty); + ty + }; + + debug!("Interned type: {:?} Pointer: {:?}", + ty, ty as *const TyS); + ty + } + + // Interns a type/name combination, stores the resulting box in cx.interner, + // and returns the box as cast to an unsafe ptr (see comments for Ty above). + pub fn mk_ty(&self, st: TypeVariants<'tcx>) -> Ty<'tcx> { + TyCtxt::intern_ty(&self.arenas.type_, &self.interner, st) + } + + pub fn mk_mach_int(&self, tm: ast::IntTy) -> Ty<'tcx> { + match tm { + ast::IntTy::Is => self.types.isize, + ast::IntTy::I8 => self.types.i8, + ast::IntTy::I16 => self.types.i16, + ast::IntTy::I32 => self.types.i32, + ast::IntTy::I64 => self.types.i64, + } + } + + pub fn mk_mach_uint(&self, tm: ast::UintTy) -> Ty<'tcx> { + match tm { + ast::UintTy::Us => self.types.usize, + ast::UintTy::U8 => self.types.u8, + ast::UintTy::U16 => self.types.u16, + ast::UintTy::U32 => self.types.u32, + ast::UintTy::U64 => self.types.u64, + } + } + + pub fn mk_mach_float(&self, tm: ast::FloatTy) -> Ty<'tcx> { + match tm { + ast::FloatTy::F32 => self.types.f32, + ast::FloatTy::F64 => self.types.f64, + } + } + + pub fn mk_str(&self) -> Ty<'tcx> { + self.mk_ty(TyStr) + } + + pub fn mk_static_str(&self) -> Ty<'tcx> { + self.mk_imm_ref(self.mk_region(ty::ReStatic), self.mk_str()) + } + + pub fn mk_enum(&self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { + // take a copy of substs so that we own the vectors inside + self.mk_ty(TyEnum(def, substs)) + } + + pub fn mk_box(&self, ty: Ty<'tcx>) -> Ty<'tcx> { + self.mk_ty(TyBox(ty)) + } + + pub fn mk_ptr(&self, tm: TypeAndMut<'tcx>) -> Ty<'tcx> { + self.mk_ty(TyRawPtr(tm)) + } + + pub fn mk_ref(&self, r: &'tcx Region, tm: TypeAndMut<'tcx>) -> Ty<'tcx> { + self.mk_ty(TyRef(r, tm)) + } + + pub fn mk_mut_ref(&self, r: &'tcx Region, ty: Ty<'tcx>) -> Ty<'tcx> { + self.mk_ref(r, TypeAndMut {ty: ty, mutbl: hir::MutMutable}) + } + + pub fn mk_imm_ref(&self, r: &'tcx Region, ty: Ty<'tcx>) -> Ty<'tcx> { + self.mk_ref(r, TypeAndMut {ty: ty, mutbl: hir::MutImmutable}) + } + + pub fn mk_mut_ptr(&self, ty: Ty<'tcx>) -> Ty<'tcx> { + self.mk_ptr(TypeAndMut {ty: ty, mutbl: hir::MutMutable}) + } + + pub fn mk_imm_ptr(&self, ty: Ty<'tcx>) -> Ty<'tcx> { + self.mk_ptr(TypeAndMut {ty: ty, mutbl: hir::MutImmutable}) + } + + pub fn mk_nil_ptr(&self) -> Ty<'tcx> { + self.mk_imm_ptr(self.mk_nil()) + } + + pub fn mk_array(&self, ty: Ty<'tcx>, n: usize) -> Ty<'tcx> { + self.mk_ty(TyArray(ty, n)) + } + + pub fn mk_slice(&self, ty: Ty<'tcx>) -> Ty<'tcx> { + self.mk_ty(TySlice(ty)) + } + + pub fn mk_tup(&self, ts: Vec>) -> Ty<'tcx> { + self.mk_ty(TyTuple(ts)) + } + + pub fn mk_nil(&self) -> Ty<'tcx> { + self.mk_tup(Vec::new()) + } + + pub fn mk_bool(&self) -> Ty<'tcx> { + self.mk_ty(TyBool) + } + + pub fn mk_fn_def(&self, def_id: DefId, + substs: &'tcx Substs<'tcx>, + fty: BareFnTy<'tcx>) -> Ty<'tcx> { + self.mk_ty(TyFnDef(def_id, substs, self.mk_bare_fn(fty))) + } + + pub fn mk_fn_ptr(&self, fty: BareFnTy<'tcx>) -> Ty<'tcx> { + self.mk_ty(TyFnPtr(self.mk_bare_fn(fty))) + } + + pub fn mk_trait(&self, + principal: ty::PolyTraitRef<'tcx>, + bounds: ExistentialBounds<'tcx>) + -> Ty<'tcx> + { + assert!(bound_list_is_sorted(&bounds.projection_bounds)); + + let inner = box TraitTy { + principal: principal, + bounds: bounds + }; + self.mk_ty(TyTrait(inner)) + } + + pub fn mk_projection(&self, + trait_ref: TraitRef<'tcx>, + item_name: Name) + -> Ty<'tcx> { + // take a copy of substs so that we own the vectors inside + let inner = ProjectionTy { trait_ref: trait_ref, item_name: item_name }; + self.mk_ty(TyProjection(inner)) + } + + pub fn mk_struct(&self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { + // take a copy of substs so that we own the vectors inside + self.mk_ty(TyStruct(def, substs)) + } + + pub fn mk_closure(&self, + closure_id: DefId, + substs: &'tcx Substs<'tcx>, + tys: Vec>) + -> Ty<'tcx> { + self.mk_closure_from_closure_substs(closure_id, Box::new(ClosureSubsts { + func_substs: substs, + upvar_tys: tys + })) + } + + pub fn mk_closure_from_closure_substs(&self, + closure_id: DefId, + closure_substs: Box>) + -> Ty<'tcx> { + self.mk_ty(TyClosure(closure_id, closure_substs)) + } + + pub fn mk_var(&self, v: TyVid) -> Ty<'tcx> { + self.mk_infer(TyVar(v)) + } + + pub fn mk_int_var(&self, v: IntVid) -> Ty<'tcx> { + self.mk_infer(IntVar(v)) + } + + pub fn mk_float_var(&self, v: FloatVid) -> Ty<'tcx> { + self.mk_infer(FloatVar(v)) + } + + pub fn mk_infer(&self, it: InferTy) -> Ty<'tcx> { + self.mk_ty(TyInfer(it)) + } + + pub fn mk_param(&self, + space: subst::ParamSpace, + index: u32, + name: Name) -> Ty<'tcx> { + self.mk_ty(TyParam(ParamTy { space: space, idx: index, name: name })) + } + + pub fn mk_self_type(&self) -> Ty<'tcx> { + self.mk_param(subst::SelfSpace, 0, special_idents::type_self.name) + } + + pub fn mk_param_from_def(&self, def: &ty::TypeParameterDef) -> Ty<'tcx> { + self.mk_param(def.space, def.index, def.name) + } + + pub fn trait_items(&self, trait_did: DefId) -> Rc>> { + self.trait_items_cache.memoize(trait_did, || { + let def_ids = self.trait_item_def_ids(trait_did); + Rc::new(def_ids.iter() + .map(|d| self.impl_or_trait_item(d.def_id())) + .collect()) + }) + } + + /// Obtain the representation annotation for a struct definition. + pub fn lookup_repr_hints(&self, did: DefId) -> Rc> { + self.repr_hint_cache.memoize(did, || { + Rc::new(if did.is_local() { + self.get_attrs(did).iter().flat_map(|meta| { + attr::find_repr_attrs(self.sess.diagnostic(), meta).into_iter() + }).collect() + } else { + self.sess.cstore.repr_attrs(did) + }) + }) + } +} diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs new file mode 100644 index 00000000000..9ab48505828 --- /dev/null +++ b/src/librustc/ty/error.rs @@ -0,0 +1,343 @@ +// Copyright 2012-2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use middle::def_id::DefId; +use ty::subst; +use infer::type_variable; +use ty::{self, BoundRegion, Region, Ty, TyCtxt}; + +use std::fmt; +use syntax::abi; +use syntax::ast::{self, Name}; +use syntax::codemap::Span; +use syntax::errors::DiagnosticBuilder; + +use rustc_front::hir; + +#[derive(Clone, Copy, Debug)] +pub struct ExpectedFound { + pub expected: T, + pub found: T +} + +// Data structures used in type unification +#[derive(Clone, Debug)] +pub enum TypeError<'tcx> { + Mismatch, + UnsafetyMismatch(ExpectedFound), + AbiMismatch(ExpectedFound), + Mutability, + BoxMutability, + PtrMutability, + RefMutability, + VecMutability, + TupleSize(ExpectedFound), + FixedArraySize(ExpectedFound), + TyParamSize(ExpectedFound), + ArgCount, + RegionsDoesNotOutlive(Region, Region), + RegionsNotSame(Region, Region), + RegionsNoOverlap(Region, Region), + RegionsInsufficientlyPolymorphic(BoundRegion, Region), + RegionsOverlyPolymorphic(BoundRegion, Region), + Sorts(ExpectedFound>), + IntegerAsChar, + IntMismatch(ExpectedFound), + FloatMismatch(ExpectedFound), + Traits(ExpectedFound), + BuiltinBoundsMismatch(ExpectedFound), + VariadicMismatch(ExpectedFound), + CyclicTy, + ConvergenceMismatch(ExpectedFound), + ProjectionNameMismatched(ExpectedFound), + ProjectionBoundsLength(ExpectedFound), + TyParamDefaultMismatch(ExpectedFound>) +} + +#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] +pub enum UnconstrainedNumeric { + UnconstrainedFloat, + UnconstrainedInt, + Neither, +} + +/// Explains the source of a type err in a short, human readable way. This is meant to be placed +/// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()` +/// afterwards to present additional details, particularly when it comes to lifetime-related +/// errors. +impl<'tcx> fmt::Display for TypeError<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::TypeError::*; + fn report_maybe_different(f: &mut fmt::Formatter, + expected: String, found: String) -> fmt::Result { + // A naive approach to making sure that we're not reporting silly errors such as: + // (expected closure, found closure). + if expected == found { + write!(f, "expected {}, found a different {}", expected, found) + } else { + write!(f, "expected {}, found {}", expected, found) + } + } + + match *self { + CyclicTy => write!(f, "cyclic type of infinite size"), + Mismatch => write!(f, "types differ"), + UnsafetyMismatch(values) => { + write!(f, "expected {} fn, found {} fn", + values.expected, + values.found) + } + AbiMismatch(values) => { + write!(f, "expected {} fn, found {} fn", + values.expected, + values.found) + } + Mutability => write!(f, "values differ in mutability"), + BoxMutability => { + write!(f, "boxed values differ in mutability") + } + VecMutability => write!(f, "vectors differ in mutability"), + PtrMutability => write!(f, "pointers differ in mutability"), + RefMutability => write!(f, "references differ in mutability"), + TyParamSize(values) => { + write!(f, "expected a type with {} type params, \ + found one with {} type params", + values.expected, + values.found) + } + FixedArraySize(values) => { + write!(f, "expected an array with a fixed size of {} elements, \ + found one with {} elements", + values.expected, + values.found) + } + TupleSize(values) => { + write!(f, "expected a tuple with {} elements, \ + found one with {} elements", + values.expected, + values.found) + } + ArgCount => { + write!(f, "incorrect number of function parameters") + } + RegionsDoesNotOutlive(..) => { + write!(f, "lifetime mismatch") + } + RegionsNotSame(..) => { + write!(f, "lifetimes are not the same") + } + RegionsNoOverlap(..) => { + write!(f, "lifetimes do not intersect") + } + RegionsInsufficientlyPolymorphic(br, _) => { + write!(f, "expected bound lifetime parameter {}, \ + found concrete lifetime", br) + } + RegionsOverlyPolymorphic(br, _) => { + write!(f, "expected concrete lifetime, \ + found bound lifetime parameter {}", br) + } + Sorts(values) => ty::tls::with(|tcx| { + report_maybe_different(f, values.expected.sort_string(tcx), + values.found.sort_string(tcx)) + }), + Traits(values) => ty::tls::with(|tcx| { + report_maybe_different(f, + format!("trait `{}`", + tcx.item_path_str(values.expected)), + format!("trait `{}`", + tcx.item_path_str(values.found))) + }), + BuiltinBoundsMismatch(values) => { + if values.expected.is_empty() { + write!(f, "expected no bounds, found `{}`", + values.found) + } else if values.found.is_empty() { + write!(f, "expected bounds `{}`, found no bounds", + values.expected) + } else { + write!(f, "expected bounds `{}`, found bounds `{}`", + values.expected, + values.found) + } + } + IntegerAsChar => { + write!(f, "expected an integral type, found `char`") + } + IntMismatch(ref values) => { + write!(f, "expected `{:?}`, found `{:?}`", + values.expected, + values.found) + } + FloatMismatch(ref values) => { + write!(f, "expected `{:?}`, found `{:?}`", + values.expected, + values.found) + } + VariadicMismatch(ref values) => { + write!(f, "expected {} fn, found {} function", + if values.expected { "variadic" } else { "non-variadic" }, + if values.found { "variadic" } else { "non-variadic" }) + } + ConvergenceMismatch(ref values) => { + write!(f, "expected {} fn, found {} function", + if values.expected { "converging" } else { "diverging" }, + if values.found { "converging" } else { "diverging" }) + } + ProjectionNameMismatched(ref values) => { + write!(f, "expected {}, found {}", + values.expected, + values.found) + } + ProjectionBoundsLength(ref values) => { + write!(f, "expected {} associated type bindings, found {}", + values.expected, + values.found) + }, + TyParamDefaultMismatch(ref values) => { + write!(f, "conflicting type parameter defaults `{}` and `{}`", + values.expected.ty, + values.found.ty) + } + } + } +} + +impl<'tcx> ty::TyS<'tcx> { + fn sort_string(&self, cx: &TyCtxt) -> String { + match self.sty { + ty::TyBool | ty::TyChar | ty::TyInt(_) | + ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr => self.to_string(), + ty::TyTuple(ref tys) if tys.is_empty() => self.to_string(), + + ty::TyEnum(def, _) => format!("enum `{}`", cx.item_path_str(def.did)), + ty::TyBox(_) => "box".to_string(), + ty::TyArray(_, n) => format!("array of {} elements", n), + ty::TySlice(_) => "slice".to_string(), + ty::TyRawPtr(_) => "*-ptr".to_string(), + ty::TyRef(_, _) => "&-ptr".to_string(), + ty::TyFnDef(..) => format!("fn item"), + ty::TyFnPtr(_) => "fn pointer".to_string(), + ty::TyTrait(ref inner) => { + format!("trait {}", cx.item_path_str(inner.principal_def_id())) + } + ty::TyStruct(def, _) => { + format!("struct `{}`", cx.item_path_str(def.did)) + } + ty::TyClosure(..) => "closure".to_string(), + ty::TyTuple(_) => "tuple".to_string(), + ty::TyInfer(ty::TyVar(_)) => "inferred type".to_string(), + ty::TyInfer(ty::IntVar(_)) => "integral variable".to_string(), + ty::TyInfer(ty::FloatVar(_)) => "floating-point variable".to_string(), + ty::TyInfer(ty::FreshTy(_)) => "skolemized type".to_string(), + ty::TyInfer(ty::FreshIntTy(_)) => "skolemized integral type".to_string(), + ty::TyInfer(ty::FreshFloatTy(_)) => "skolemized floating-point type".to_string(), + ty::TyProjection(_) => "associated type".to_string(), + ty::TyParam(ref p) => { + if p.space == subst::SelfSpace { + "Self".to_string() + } else { + "type parameter".to_string() + } + } + ty::TyError => "type error".to_string(), + } + } +} + +impl<'tcx> TyCtxt<'tcx> { + pub fn note_and_explain_type_err(&self, + db: &mut DiagnosticBuilder, + err: &TypeError<'tcx>, + sp: Span) { + use self::TypeError::*; + + match err.clone() { + RegionsDoesNotOutlive(subregion, superregion) => { + self.note_and_explain_region(db, "", subregion, "..."); + self.note_and_explain_region(db, "...does not necessarily outlive ", + superregion, ""); + } + RegionsNotSame(region1, region2) => { + self.note_and_explain_region(db, "", region1, "..."); + self.note_and_explain_region(db, "...is not the same lifetime as ", + region2, ""); + } + RegionsNoOverlap(region1, region2) => { + self.note_and_explain_region(db, "", region1, "..."); + self.note_and_explain_region(db, "...does not overlap ", + region2, ""); + } + RegionsInsufficientlyPolymorphic(_, conc_region) => { + self.note_and_explain_region(db, "concrete lifetime that was found is ", + conc_region, ""); + } + RegionsOverlyPolymorphic(_, ty::ReVar(_)) => { + // don't bother to print out the message below for + // inference variables, it's not very illuminating. + } + RegionsOverlyPolymorphic(_, conc_region) => { + self.note_and_explain_region(db, "expected concrete lifetime is ", + conc_region, ""); + } + Sorts(values) => { + let expected_str = values.expected.sort_string(self); + let found_str = values.found.sort_string(self); + if expected_str == found_str && expected_str == "closure" { + db.span_note(sp, + "no two closures, even if identical, have the same type"); + db.span_help(sp, + "consider boxing your closure and/or using it as a trait object"); + } + }, + TyParamDefaultMismatch(values) => { + let expected = values.expected; + let found = values.found; + db.span_note(sp, &format!("conflicting type parameter defaults `{}` and `{}`", + expected.ty, + found.ty)); + + match + self.map.as_local_node_id(expected.def_id) + .and_then(|node_id| self.map.opt_span(node_id)) + { + Some(span) => { + db.span_note(span, "a default was defined here..."); + } + None => { + db.note(&format!("a default is defined on `{}`", + self.item_path_str(expected.def_id))); + } + } + + db.span_note( + expected.origin_span, + "...that was applied to an unconstrained type variable here"); + + match + self.map.as_local_node_id(found.def_id) + .and_then(|node_id| self.map.opt_span(node_id)) + { + Some(span) => { + db.span_note(span, "a second default was defined here..."); + } + None => { + db.note(&format!("a second default is defined on `{}`", + self.item_path_str(found.def_id))); + } + } + + db.span_note(found.origin_span, + "...that also applies to the same type variable here"); + } + _ => {} + } + } +} diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs new file mode 100644 index 00000000000..0865e059f59 --- /dev/null +++ b/src/librustc/ty/fast_reject.rs @@ -0,0 +1,103 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use middle::def_id::DefId; +use ty::{self, Ty, TyCtxt}; +use syntax::ast; + +use self::SimplifiedType::*; + +/// See `simplify_type +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum SimplifiedType { + BoolSimplifiedType, + CharSimplifiedType, + IntSimplifiedType(ast::IntTy), + UintSimplifiedType(ast::UintTy), + FloatSimplifiedType(ast::FloatTy), + EnumSimplifiedType(DefId), + StrSimplifiedType, + VecSimplifiedType, + PtrSimplifiedType, + TupleSimplifiedType(usize), + TraitSimplifiedType(DefId), + StructSimplifiedType(DefId), + ClosureSimplifiedType(DefId), + FunctionSimplifiedType(usize), + ParameterSimplifiedType, +} + +/// Tries to simplify a type by dropping type parameters, deref'ing away any reference types, etc. +/// The idea is to get something simple that we can use to quickly decide if two types could unify +/// during method lookup. +/// +/// If `can_simplify_params` is false, then we will fail to simplify type parameters entirely. This +/// is useful when those type parameters would be instantiated with fresh type variables, since +/// then we can't say much about whether two types would unify. Put another way, +/// `can_simplify_params` should be true if type parameters appear free in `ty` and `false` if they +/// are to be considered bound. +pub fn simplify_type(tcx: &TyCtxt, + ty: Ty, + can_simplify_params: bool) + -> Option +{ + match ty.sty { + ty::TyBool => Some(BoolSimplifiedType), + ty::TyChar => Some(CharSimplifiedType), + ty::TyInt(int_type) => Some(IntSimplifiedType(int_type)), + ty::TyUint(uint_type) => Some(UintSimplifiedType(uint_type)), + ty::TyFloat(float_type) => Some(FloatSimplifiedType(float_type)), + ty::TyEnum(def, _) => Some(EnumSimplifiedType(def.did)), + ty::TyStr => Some(StrSimplifiedType), + ty::TyArray(..) | ty::TySlice(_) => Some(VecSimplifiedType), + ty::TyRawPtr(_) => Some(PtrSimplifiedType), + ty::TyTrait(ref trait_info) => { + Some(TraitSimplifiedType(trait_info.principal_def_id())) + } + ty::TyStruct(def, _) => { + Some(StructSimplifiedType(def.did)) + } + ty::TyRef(_, mt) => { + // since we introduce auto-refs during method lookup, we + // just treat &T and T as equivalent from the point of + // view of possibly unifying + simplify_type(tcx, mt.ty, can_simplify_params) + } + ty::TyBox(_) => { + // treat like we would treat `Box` + match tcx.lang_items.require_owned_box() { + Ok(def_id) => Some(StructSimplifiedType(def_id)), + Err(msg) => tcx.sess.fatal(&msg), + } + } + ty::TyClosure(def_id, _) => { + Some(ClosureSimplifiedType(def_id)) + } + ty::TyTuple(ref tys) => { + Some(TupleSimplifiedType(tys.len())) + } + ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => { + Some(FunctionSimplifiedType(f.sig.0.inputs.len())) + } + ty::TyProjection(_) | ty::TyParam(_) => { + if can_simplify_params { + // In normalized types, projections don't unify with + // anything. when lazy normalization happens, this + // will change. It would still be nice to have a way + // to deal with known-not-to-unify-with-anything + // projections (e.g. the likes of <__S as Encoder>::Error). + Some(ParameterSimplifiedType) + } else { + None + } + } + ty::TyInfer(_) | ty::TyError => None, + } +} diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs new file mode 100644 index 00000000000..f3dcccedc59 --- /dev/null +++ b/src/librustc/ty/flags.rs @@ -0,0 +1,205 @@ +// Copyright 2012-2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ty::subst; +use ty::{self, Ty, TypeFlags, TypeFoldable}; + +pub struct FlagComputation { + pub flags: TypeFlags, + + // maximum depth of any bound region that we have seen thus far + pub depth: u32, +} + +impl FlagComputation { + fn new() -> FlagComputation { + FlagComputation { flags: TypeFlags::empty(), depth: 0 } + } + + pub fn for_sty(st: &ty::TypeVariants) -> FlagComputation { + let mut result = FlagComputation::new(); + result.add_sty(st); + result + } + + fn add_flags(&mut self, flags: TypeFlags) { + self.flags = self.flags | (flags & TypeFlags::NOMINAL_FLAGS); + } + + fn add_depth(&mut self, depth: u32) { + if depth > self.depth { + self.depth = depth; + } + } + + /// Adds the flags/depth from a set of types that appear within the current type, but within a + /// region binder. + fn add_bound_computation(&mut self, computation: &FlagComputation) { + self.add_flags(computation.flags); + + // The types that contributed to `computation` occurred within + // a region binder, so subtract one from the region depth + // within when adding the depth to `self`. + let depth = computation.depth; + if depth > 0 { + self.add_depth(depth - 1); + } + } + + fn add_sty(&mut self, st: &ty::TypeVariants) { + match st { + &ty::TyBool | + &ty::TyChar | + &ty::TyInt(_) | + &ty::TyFloat(_) | + &ty::TyUint(_) | + &ty::TyStr => { + } + + // You might think that we could just return TyError for + // any type containing TyError as a component, and get + // rid of the TypeFlags::HAS_TY_ERR flag -- likewise for ty_bot (with + // the exception of function types that return bot). + // But doing so caused sporadic memory corruption, and + // neither I (tjc) nor nmatsakis could figure out why, + // so we're doing it this way. + &ty::TyError => { + self.add_flags(TypeFlags::HAS_TY_ERR) + } + + &ty::TyParam(ref p) => { + self.add_flags(TypeFlags::HAS_LOCAL_NAMES); + if p.space == subst::SelfSpace { + self.add_flags(TypeFlags::HAS_SELF); + } else { + self.add_flags(TypeFlags::HAS_PARAMS); + } + } + + &ty::TyClosure(_, ref substs) => { + self.add_flags(TypeFlags::HAS_TY_CLOSURE); + self.add_flags(TypeFlags::HAS_LOCAL_NAMES); + self.add_substs(&substs.func_substs); + self.add_tys(&substs.upvar_tys); + } + + &ty::TyInfer(_) => { + self.add_flags(TypeFlags::HAS_LOCAL_NAMES); // it might, right? + self.add_flags(TypeFlags::HAS_TY_INFER) + } + + &ty::TyEnum(_, substs) | &ty::TyStruct(_, substs) => { + self.add_substs(substs); + } + + &ty::TyProjection(ref data) => { + self.add_flags(TypeFlags::HAS_PROJECTION); + self.add_projection_ty(data); + } + + &ty::TyTrait(box ty::TraitTy { ref principal, ref bounds }) => { + let mut computation = FlagComputation::new(); + computation.add_substs(principal.0.substs); + for projection_bound in &bounds.projection_bounds { + let mut proj_computation = FlagComputation::new(); + proj_computation.add_projection_predicate(&projection_bound.0); + self.add_bound_computation(&proj_computation); + } + self.add_bound_computation(&computation); + + self.add_bounds(bounds); + } + + &ty::TyBox(tt) | &ty::TyArray(tt, _) | &ty::TySlice(tt) => { + self.add_ty(tt) + } + + &ty::TyRawPtr(ref m) => { + self.add_ty(m.ty); + } + + &ty::TyRef(r, ref m) => { + self.add_region(*r); + self.add_ty(m.ty); + } + + &ty::TyTuple(ref ts) => { + self.add_tys(&ts[..]); + } + + &ty::TyFnDef(_, substs, ref f) => { + self.add_substs(substs); + self.add_fn_sig(&f.sig); + } + + &ty::TyFnPtr(ref f) => { + self.add_fn_sig(&f.sig); + } + } + } + + fn add_ty(&mut self, ty: Ty) { + self.add_flags(ty.flags.get()); + self.add_depth(ty.region_depth); + } + + fn add_tys(&mut self, tys: &[Ty]) { + for &ty in tys { + self.add_ty(ty); + } + } + + fn add_fn_sig(&mut self, fn_sig: &ty::PolyFnSig) { + let mut computation = FlagComputation::new(); + + computation.add_tys(&fn_sig.0.inputs); + + if let ty::FnConverging(output) = fn_sig.0.output { + computation.add_ty(output); + } + + self.add_bound_computation(&computation); + } + + fn add_region(&mut self, r: ty::Region) { + match r { + ty::ReVar(..) | + ty::ReSkolemized(..) => { self.add_flags(TypeFlags::HAS_RE_INFER); } + ty::ReLateBound(debruijn, _) => { self.add_depth(debruijn.depth); } + ty::ReEarlyBound(..) => { self.add_flags(TypeFlags::HAS_RE_EARLY_BOUND); } + ty::ReStatic => {} + _ => { self.add_flags(TypeFlags::HAS_FREE_REGIONS); } + } + + if !r.is_global() { + self.add_flags(TypeFlags::HAS_LOCAL_NAMES); + } + } + + fn add_projection_predicate(&mut self, projection_predicate: &ty::ProjectionPredicate) { + self.add_projection_ty(&projection_predicate.projection_ty); + self.add_ty(projection_predicate.ty); + } + + fn add_projection_ty(&mut self, projection_ty: &ty::ProjectionTy) { + self.add_substs(projection_ty.trait_ref.substs); + } + + fn add_substs(&mut self, substs: &subst::Substs) { + self.add_tys(substs.types.as_slice()); + for &r in &substs.regions { + self.add_region(r); + } + } + + fn add_bounds(&mut self, bounds: &ty::ExistentialBounds) { + self.add_region(bounds.region_bound); + } +} diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs new file mode 100644 index 00000000000..d04f272688c --- /dev/null +++ b/src/librustc/ty/fold.rs @@ -0,0 +1,642 @@ +// Copyright 2012-2013 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Generalized type folding mechanism. The setup is a bit convoluted +//! but allows for convenient usage. Let T be an instance of some +//! "foldable type" (one which implements `TypeFoldable`) and F be an +//! instance of a "folder" (a type which implements `TypeFolder`). Then +//! the setup is intended to be: +//! +//! T.fold_with(F) --calls--> F.fold_T(T) --calls--> T.super_fold_with(F) +//! +//! This way, when you define a new folder F, you can override +//! `fold_T()` to customize the behavior, and invoke `T.super_fold_with()` +//! to get the original behavior. Meanwhile, to actually fold +//! something, you can just write `T.fold_with(F)`, which is +//! convenient. (Note that `fold_with` will also transparently handle +//! things like a `Vec` where T is foldable and so on.) +//! +//! In this ideal setup, the only function that actually *does* +//! anything is `T.super_fold_with()`, which traverses the type `T`. +//! Moreover, `T.super_fold_with()` should only ever call `T.fold_with()`. +//! +//! In some cases, we follow a degenerate pattern where we do not have +//! a `fold_T` method. Instead, `T.fold_with` traverses the structure directly. +//! This is suboptimal because the behavior cannot be overridden, but it's +//! much less work to implement. If you ever *do* need an override that +//! doesn't exist, it's not hard to convert the degenerate pattern into the +//! proper thing. +//! +//! A `TypeFoldable` T can also be visited by a `TypeVisitor` V using similar setup: +//! T.visit_with(V) --calls--> V.visit_T(T) --calls--> T.super_visit_with(V). +//! These methods return true to indicate that the visitor has found what it is looking for +//! and does not need to visit anything else. + +use middle::region; +use ty::subst; +use ty::adjustment; +use ty::{self, Binder, Ty, TyCtxt, TypeFlags}; + +use std::fmt; +use util::nodemap::{FnvHashMap, FnvHashSet}; + +/// The TypeFoldable trait is implemented for every type that can be folded. +/// Basically, every type that has a corresponding method in TypeFolder. +pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { + fn super_fold_with>(&self, folder: &mut F) -> Self; + fn fold_with>(&self, folder: &mut F) -> Self { + self.super_fold_with(folder) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool; + fn visit_with>(&self, visitor: &mut V) -> bool { + self.super_visit_with(visitor) + } + + fn has_regions_escaping_depth(&self, depth: u32) -> bool { + self.visit_with(&mut HasEscapingRegionsVisitor { depth: depth }) + } + fn has_escaping_regions(&self) -> bool { + self.has_regions_escaping_depth(0) + } + + fn has_type_flags(&self, flags: TypeFlags) -> bool { + self.visit_with(&mut HasTypeFlagsVisitor { flags: flags }) + } + fn has_projection_types(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_PROJECTION) + } + fn references_error(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_ERR) + } + fn has_param_types(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_PARAMS) + } + fn has_self_ty(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_SELF) + } + fn has_infer_types(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_INFER) + } + fn needs_infer(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER) + } + fn needs_subst(&self) -> bool { + self.has_type_flags(TypeFlags::NEEDS_SUBST) + } + fn has_closure_types(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_CLOSURE) + } + fn has_erasable_regions(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_RE_EARLY_BOUND | + TypeFlags::HAS_RE_INFER | + TypeFlags::HAS_FREE_REGIONS) + } + /// Indicates whether this value references only 'global' + /// types/lifetimes that are the same regardless of what fn we are + /// in. This is used for caching. Errs on the side of returning + /// false. + fn is_global(&self) -> bool { + !self.has_type_flags(TypeFlags::HAS_LOCAL_NAMES) + } +} + +/// The TypeFolder trait defines the actual *folding*. There is a +/// method defined for every foldable type. Each of these has a +/// default implementation that does an "identity" fold. Within each +/// identity fold, it should invoke `foo.fold_with(self)` to fold each +/// sub-item. +pub trait TypeFolder<'tcx> : Sized { + fn tcx<'a>(&'a self) -> &'a TyCtxt<'tcx>; + + /// Invoked by the `super_*` routines when we enter a region + /// binding level (for example, when entering a function + /// signature). This is used by clients that want to track the + /// Debruijn index nesting level. + fn enter_region_binder(&mut self) { } + + /// Invoked by the `super_*` routines when we exit a region + /// binding level. This is used by clients that want to + /// track the Debruijn index nesting level. + fn exit_region_binder(&mut self) { } + + fn fold_binder(&mut self, t: &Binder) -> Binder + where T : TypeFoldable<'tcx> + { + // FIXME(#20526) this should replace `enter_region_binder`/`exit_region_binder`. + t.super_fold_with(self) + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + t.super_fold_with(self) + } + + fn fold_mt(&mut self, t: &ty::TypeAndMut<'tcx>) -> ty::TypeAndMut<'tcx> { + t.super_fold_with(self) + } + + fn fold_trait_ref(&mut self, t: &ty::TraitRef<'tcx>) -> ty::TraitRef<'tcx> { + t.super_fold_with(self) + } + + fn fold_impl_header(&mut self, imp: &ty::ImplHeader<'tcx>) -> ty::ImplHeader<'tcx> { + imp.super_fold_with(self) + } + + fn fold_substs(&mut self, + substs: &subst::Substs<'tcx>) + -> subst::Substs<'tcx> { + substs.super_fold_with(self) + } + + fn fold_fn_sig(&mut self, + sig: &ty::FnSig<'tcx>) + -> ty::FnSig<'tcx> { + sig.super_fold_with(self) + } + + fn fold_output(&mut self, + output: &ty::FnOutput<'tcx>) + -> ty::FnOutput<'tcx> { + output.super_fold_with(self) + } + + fn fold_bare_fn_ty(&mut self, + fty: &ty::BareFnTy<'tcx>) + -> ty::BareFnTy<'tcx> + { + fty.super_fold_with(self) + } + + fn fold_closure_ty(&mut self, + fty: &ty::ClosureTy<'tcx>) + -> ty::ClosureTy<'tcx> { + fty.super_fold_with(self) + } + + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + r.super_fold_with(self) + } + + fn fold_existential_bounds(&mut self, s: &ty::ExistentialBounds<'tcx>) + -> ty::ExistentialBounds<'tcx> { + s.super_fold_with(self) + } + + fn fold_autoref(&mut self, ar: &adjustment::AutoRef<'tcx>) + -> adjustment::AutoRef<'tcx> { + ar.super_fold_with(self) + } +} + +pub trait TypeVisitor<'tcx> : Sized { + fn enter_region_binder(&mut self) { } + fn exit_region_binder(&mut self) { } + + fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + t.super_visit_with(self) + } + + fn visit_region(&mut self, r: ty::Region) -> bool { + r.super_visit_with(self) + } +} + +/////////////////////////////////////////////////////////////////////////// +// Some sample folders + +pub struct BottomUpFolder<'a, 'tcx: 'a, F> where F: FnMut(Ty<'tcx>) -> Ty<'tcx> { + pub tcx: &'a TyCtxt<'tcx>, + pub fldop: F, +} + +impl<'a, 'tcx, F> TypeFolder<'tcx> for BottomUpFolder<'a, 'tcx, F> where + F: FnMut(Ty<'tcx>) -> Ty<'tcx>, +{ + fn tcx(&self) -> &TyCtxt<'tcx> { self.tcx } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + let t1 = ty.super_fold_with(self); + (self.fldop)(t1) + } +} + +/////////////////////////////////////////////////////////////////////////// +// Region folder + +impl<'tcx> TyCtxt<'tcx> { + /// Collects the free and escaping regions in `value` into `region_set`. Returns + /// whether any late-bound regions were skipped + pub fn collect_regions(&self, + value: &T, + region_set: &mut FnvHashSet) + -> bool + where T : TypeFoldable<'tcx> + { + let mut have_bound_regions = false; + self.fold_regions(value, &mut have_bound_regions, + |r, d| { region_set.insert(r.from_depth(d)); r }); + have_bound_regions + } + + /// Folds the escaping and free regions in `value` using `f`, and + /// sets `skipped_regions` to true if any late-bound region was found + /// and skipped. + pub fn fold_regions(&self, + value: &T, + skipped_regions: &mut bool, + mut f: F) + -> T + where F : FnMut(ty::Region, u32) -> ty::Region, + T : TypeFoldable<'tcx>, + { + value.fold_with(&mut RegionFolder::new(self, skipped_regions, &mut f)) + } +} + +/// Folds over the substructure of a type, visiting its component +/// types and all regions that occur *free* within it. +/// +/// That is, `Ty` can contain function or method types that bind +/// regions at the call site (`ReLateBound`), and occurrences of +/// regions (aka "lifetimes") that are bound within a type are not +/// visited by this folder; only regions that occur free will be +/// visited by `fld_r`. + +pub struct RegionFolder<'a, 'tcx: 'a> { + tcx: &'a TyCtxt<'tcx>, + skipped_regions: &'a mut bool, + current_depth: u32, + fld_r: &'a mut (FnMut(ty::Region, u32) -> ty::Region + 'a), +} + +impl<'a, 'tcx> RegionFolder<'a, 'tcx> { + pub fn new(tcx: &'a TyCtxt<'tcx>, + skipped_regions: &'a mut bool, + fld_r: &'a mut F) -> RegionFolder<'a, 'tcx> + where F : FnMut(ty::Region, u32) -> ty::Region + { + RegionFolder { + tcx: tcx, + skipped_regions: skipped_regions, + current_depth: 1, + fld_r: fld_r, + } + } +} + +impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> +{ + fn tcx(&self) -> &TyCtxt<'tcx> { self.tcx } + + fn enter_region_binder(&mut self) { + self.current_depth += 1; + } + + fn exit_region_binder(&mut self) { + self.current_depth -= 1; + } + + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + match r { + ty::ReLateBound(debruijn, _) if debruijn.depth < self.current_depth => { + debug!("RegionFolder.fold_region({:?}) skipped bound region (current depth={})", + r, self.current_depth); + *self.skipped_regions = true; + r + } + _ => { + debug!("RegionFolder.fold_region({:?}) folding free region (current_depth={})", + r, self.current_depth); + (self.fld_r)(r, self.current_depth) + } + } + } +} + +/////////////////////////////////////////////////////////////////////////// +// Late-bound region replacer + +// Replaces the escaping regions in a type. + +struct RegionReplacer<'a, 'tcx: 'a> { + tcx: &'a TyCtxt<'tcx>, + current_depth: u32, + fld_r: &'a mut (FnMut(ty::BoundRegion) -> ty::Region + 'a), + map: FnvHashMap +} + +impl<'tcx> TyCtxt<'tcx> { + pub fn replace_late_bound_regions(&self, + value: &Binder, + mut f: F) + -> (T, FnvHashMap) + where F : FnMut(ty::BoundRegion) -> ty::Region, + T : TypeFoldable<'tcx>, + { + debug!("replace_late_bound_regions({:?})", value); + let mut replacer = RegionReplacer::new(self, &mut f); + let result = value.skip_binder().fold_with(&mut replacer); + (result, replacer.map) + } + + + /// Replace any late-bound regions bound in `value` with free variants attached to scope-id + /// `scope_id`. + pub fn liberate_late_bound_regions(&self, + all_outlive_scope: region::CodeExtent, + value: &Binder) + -> T + where T : TypeFoldable<'tcx> + { + self.replace_late_bound_regions(value, |br| { + ty::ReFree(ty::FreeRegion{scope: all_outlive_scope, bound_region: br}) + }).0 + } + + /// Flattens two binding levels into one. So `for<'a> for<'b> Foo` + /// becomes `for<'a,'b> Foo`. + pub fn flatten_late_bound_regions(&self, bound2_value: &Binder>) + -> Binder + where T: TypeFoldable<'tcx> + { + let bound0_value = bound2_value.skip_binder().skip_binder(); + let value = self.fold_regions(bound0_value, &mut false, + |region, current_depth| { + match region { + ty::ReLateBound(debruijn, br) if debruijn.depth >= current_depth => { + // should be true if no escaping regions from bound2_value + assert!(debruijn.depth - current_depth <= 1); + ty::ReLateBound(ty::DebruijnIndex::new(current_depth), br) + } + _ => { + region + } + } + }); + Binder(value) + } + + pub fn no_late_bound_regions(&self, value: &Binder) -> Option + where T : TypeFoldable<'tcx> + { + if value.0.has_escaping_regions() { + None + } else { + Some(value.0.clone()) + } + } + + /// Replace any late-bound regions bound in `value` with `'static`. Useful in trans but also + /// method lookup and a few other places where precise region relationships are not required. + pub fn erase_late_bound_regions(&self, value: &Binder) -> T + where T : TypeFoldable<'tcx> + { + self.replace_late_bound_regions(value, |_| ty::ReStatic).0 + } + + /// Rewrite any late-bound regions so that they are anonymous. Region numbers are + /// assigned starting at 1 and increasing monotonically in the order traversed + /// by the fold operation. + /// + /// The chief purpose of this function is to canonicalize regions so that two + /// `FnSig`s or `TraitRef`s which are equivalent up to region naming will become + /// structurally identical. For example, `for<'a, 'b> fn(&'a isize, &'b isize)` and + /// `for<'a, 'b> fn(&'b isize, &'a isize)` will become identical after anonymization. + pub fn anonymize_late_bound_regions(&self, sig: &Binder) -> Binder + where T : TypeFoldable<'tcx>, + { + let mut counter = 0; + Binder(self.replace_late_bound_regions(sig, |_| { + counter += 1; + ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrAnon(counter)) + }).0) + } +} + +impl<'a, 'tcx> RegionReplacer<'a, 'tcx> { + fn new(tcx: &'a TyCtxt<'tcx>, fld_r: &'a mut F) -> RegionReplacer<'a, 'tcx> + where F : FnMut(ty::BoundRegion) -> ty::Region + { + RegionReplacer { + tcx: tcx, + current_depth: 1, + fld_r: fld_r, + map: FnvHashMap() + } + } +} + +impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx> +{ + fn tcx(&self) -> &TyCtxt<'tcx> { self.tcx } + + fn enter_region_binder(&mut self) { + self.current_depth += 1; + } + + fn exit_region_binder(&mut self) { + self.current_depth -= 1; + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + if !t.has_regions_escaping_depth(self.current_depth-1) { + return t; + } + + t.super_fold_with(self) + } + + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + match r { + ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => { + debug!("RegionReplacer.fold_region({:?}) folding region (current_depth={})", + r, self.current_depth); + let fld_r = &mut self.fld_r; + let region = *self.map.entry(br).or_insert_with(|| fld_r(br)); + if let ty::ReLateBound(debruijn1, br) = region { + // If the callback returns a late-bound region, + // that region should always use depth 1. Then we + // adjust it to the correct depth. + assert_eq!(debruijn1.depth, 1); + ty::ReLateBound(debruijn, br) + } else { + region + } + } + r => r + } + } +} + +/////////////////////////////////////////////////////////////////////////// +// Region eraser + +impl<'tcx> TyCtxt<'tcx> { + /// Returns an equivalent value with all free regions removed (note + /// that late-bound regions remain, because they are important for + /// subtyping, but they are anonymized and normalized as well).. + pub fn erase_regions(&self, value: &T) -> T + where T : TypeFoldable<'tcx> + { + let value1 = value.fold_with(&mut RegionEraser(self)); + debug!("erase_regions({:?}) = {:?}", + value, value1); + return value1; + + struct RegionEraser<'a, 'tcx: 'a>(&'a TyCtxt<'tcx>); + + impl<'a, 'tcx> TypeFolder<'tcx> for RegionEraser<'a, 'tcx> { + fn tcx(&self) -> &TyCtxt<'tcx> { self.0 } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + match self.tcx().normalized_cache.borrow().get(&ty).cloned() { + None => {} + Some(u) => return u + } + + let t_norm = ty.super_fold_with(self); + self.tcx().normalized_cache.borrow_mut().insert(ty, t_norm); + return t_norm; + } + + fn fold_binder(&mut self, t: &ty::Binder) -> ty::Binder + where T : TypeFoldable<'tcx> + { + let u = self.tcx().anonymize_late_bound_regions(t); + u.super_fold_with(self) + } + + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + // because late-bound regions affect subtyping, we can't + // erase the bound/free distinction, but we can replace + // all free regions with 'static. + // + // Note that we *CAN* replace early-bound regions -- the + // type system never "sees" those, they get substituted + // away. In trans, they will always be erased to 'static + // whenever a substitution occurs. + match r { + ty::ReLateBound(..) => r, + _ => ty::ReStatic + } + } + + fn fold_substs(&mut self, + substs: &subst::Substs<'tcx>) + -> subst::Substs<'tcx> { + subst::Substs { regions: substs.regions.fold_with(self), + types: substs.types.fold_with(self) } + } + } + } +} + +/////////////////////////////////////////////////////////////////////////// +// Region shifter +// +// Shifts the De Bruijn indices on all escaping bound regions by a +// fixed amount. Useful in substitution or when otherwise introducing +// a binding level that is not intended to capture the existing bound +// regions. See comment on `shift_regions_through_binders` method in +// `subst.rs` for more details. + +pub fn shift_region(region: ty::Region, amount: u32) -> ty::Region { + match region { + ty::ReLateBound(debruijn, br) => { + ty::ReLateBound(debruijn.shifted(amount), br) + } + _ => { + region + } + } +} + +pub fn shift_regions<'tcx, T:TypeFoldable<'tcx>>(tcx: &TyCtxt<'tcx>, + amount: u32, value: &T) -> T { + debug!("shift_regions(value={:?}, amount={})", + value, amount); + + value.fold_with(&mut RegionFolder::new(tcx, &mut false, &mut |region, _current_depth| { + shift_region(region, amount) + })) +} + +/// An "escaping region" is a bound region whose binder is not part of `t`. +/// +/// So, for example, consider a type like the following, which has two binders: +/// +/// for<'a> fn(x: for<'b> fn(&'a isize, &'b isize)) +/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ outer scope +/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ inner scope +/// +/// This type has *bound regions* (`'a`, `'b`), but it does not have escaping regions, because the +/// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner +/// fn type*, that type has an escaping region: `'a`. +/// +/// Note that what I'm calling an "escaping region" is often just called a "free region". However, +/// we already use the term "free region". It refers to the regions that we use to represent bound +/// regions on a fn definition while we are typechecking its body. +/// +/// To clarify, conceptually there is no particular difference between an "escaping" region and a +/// "free" region. However, there is a big difference in practice. Basically, when "entering" a +/// binding level, one is generally required to do some sort of processing to a bound region, such +/// as replacing it with a fresh/skolemized region, or making an entry in the environment to +/// represent the scope to which it is attached, etc. An escaping region represents a bound region +/// for which this processing has not yet been done. +struct HasEscapingRegionsVisitor { + depth: u32, +} + +impl<'tcx> TypeVisitor<'tcx> for HasEscapingRegionsVisitor { + fn enter_region_binder(&mut self) { + self.depth += 1; + } + + fn exit_region_binder(&mut self) { + self.depth -= 1; + } + + fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + t.region_depth > self.depth + } + + fn visit_region(&mut self, r: ty::Region) -> bool { + r.escapes_depth(self.depth) + } +} + +struct HasTypeFlagsVisitor { + flags: ty::TypeFlags, +} + +impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { + fn visit_ty(&mut self, t: Ty) -> bool { + t.flags.get().intersects(self.flags) + } + + fn visit_region(&mut self, r: ty::Region) -> bool { + if self.flags.intersects(ty::TypeFlags::HAS_LOCAL_NAMES) { + // does this represent a region that cannot be named + // in a global way? used in fulfillment caching. + match r { + ty::ReStatic | ty::ReEmpty => {} + _ => return true, + } + } + if self.flags.intersects(ty::TypeFlags::HAS_RE_INFER) { + match r { + ty::ReVar(_) | ty::ReSkolemized(..) => { return true } + _ => {} + } + } + false + } +} diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs new file mode 100644 index 00000000000..a106fd6e5aa --- /dev/null +++ b/src/librustc/ty/item_path.rs @@ -0,0 +1,317 @@ +// Copyright 2012-2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use front::map::DefPathData; +use middle::cstore::LOCAL_CRATE; +use middle::def_id::DefId; +use ty::{self, Ty, TyCtxt}; +use syntax::ast; + +impl<'tcx> TyCtxt<'tcx> { + /// Returns a string identifying this def-id. This string is + /// suitable for user output. It is relative to the current crate + /// root. + pub fn item_path_str(&self, def_id: DefId) -> String { + let mut buffer = LocalPathBuffer::new(RootMode::Local); + self.push_item_path(&mut buffer, def_id); + buffer.into_string() + } + + /// Returns a string identifying this def-id. This string is + /// suitable for user output. It always begins with a crate identifier. + pub fn absolute_item_path_str(&self, def_id: DefId) -> String { + let mut buffer = LocalPathBuffer::new(RootMode::Absolute); + self.push_item_path(&mut buffer, def_id); + buffer.into_string() + } + + /// Returns the "path" to a particular crate. This can proceed in + /// various ways, depending on the `root_mode` of the `buffer`. + /// (See `RootMode` enum for more details.) + pub fn push_krate_path(&self, buffer: &mut T, cnum: ast::CrateNum) + where T: ItemPathBuffer + { + match *buffer.root_mode() { + RootMode::Local => { + // In local mode, when we encounter a crate other than + // LOCAL_CRATE, execution proceeds in one of two ways: + // + // 1. for a direct dependency, where user added an + // `extern crate` manually, we put the `extern + // crate` as the parent. So you wind up with + // something relative to the current crate. + // 2. for an indirect crate, where there is no extern + // crate, we just prepend the crate name. + // + // Returns `None` for the local crate. + if cnum != LOCAL_CRATE { + let opt_extern_crate = self.sess.cstore.extern_crate(cnum); + let opt_extern_crate = opt_extern_crate.and_then(|extern_crate| { + if extern_crate.direct { + Some(extern_crate.def_id) + } else { + None + } + }); + if let Some(extern_crate_def_id) = opt_extern_crate { + self.push_item_path(buffer, extern_crate_def_id); + } else { + buffer.push(&self.crate_name(cnum)); + } + } + } + RootMode::Absolute => { + // In absolute mode, just write the crate name + // unconditionally. + buffer.push(&self.crate_name(cnum)); + } + } + } + + pub fn push_item_path(&self, buffer: &mut T, def_id: DefId) + where T: ItemPathBuffer + { + let key = self.def_key(def_id); + match key.disambiguated_data.data { + DefPathData::CrateRoot => { + assert!(key.parent.is_none()); + self.push_krate_path(buffer, def_id.krate); + } + + DefPathData::InlinedRoot(ref root_path) => { + assert!(key.parent.is_none()); + self.push_item_path(buffer, root_path.def_id); + } + + DefPathData::Impl => { + self.push_impl_path(buffer, def_id); + } + + // Unclear if there is any value in distinguishing these. + // Probably eventually (and maybe we would even want + // finer-grained distinctions, e.g. between enum/struct). + data @ DefPathData::Misc | + data @ DefPathData::TypeNs(..) | + data @ DefPathData::ValueNs(..) | + data @ DefPathData::TypeParam(..) | + data @ DefPathData::LifetimeDef(..) | + data @ DefPathData::EnumVariant(..) | + data @ DefPathData::Field(..) | + data @ DefPathData::StructCtor | + data @ DefPathData::Initializer | + data @ DefPathData::MacroDef(..) | + data @ DefPathData::ClosureExpr | + data @ DefPathData::Binding(..) => { + let parent_def_id = self.parent_def_id(def_id).unwrap(); + self.push_item_path(buffer, parent_def_id); + buffer.push(&data.as_interned_str()); + } + } + } + + fn push_impl_path(&self, + buffer: &mut T, + impl_def_id: DefId) + where T: ItemPathBuffer + { + let parent_def_id = self.parent_def_id(impl_def_id).unwrap(); + + let use_types = if !impl_def_id.is_local() { + // always have full types available for extern crates + true + } else { + // for local crates, check whether type info is + // available; typeck might not have completed yet + self.impl_trait_refs.borrow().contains_key(&impl_def_id) + }; + + if !use_types { + return self.push_impl_path_fallback(buffer, impl_def_id); + } + + // Decide whether to print the parent path for the impl. + // Logically, since impls are global, it's never needed, but + // users may find it useful. Currently, we omit the parent if + // the impl is either in the same module as the self-type or + // as the trait. + let self_ty = self.lookup_item_type(impl_def_id).ty; + let in_self_mod = match self.characteristic_def_id_of_type(self_ty) { + None => false, + Some(ty_def_id) => self.parent_def_id(ty_def_id) == Some(parent_def_id), + }; + + let impl_trait_ref = self.impl_trait_ref(impl_def_id); + let in_trait_mod = match impl_trait_ref { + None => false, + Some(trait_ref) => self.parent_def_id(trait_ref.def_id) == Some(parent_def_id), + }; + + if !in_self_mod && !in_trait_mod { + // If the impl is not co-located with either self-type or + // trait-type, then fallback to a format that identifies + // the module more clearly. + self.push_item_path(buffer, parent_def_id); + if let Some(trait_ref) = impl_trait_ref { + buffer.push(&format!("", trait_ref, self_ty)); + } else { + buffer.push(&format!("", self_ty)); + } + return; + } + + // Otherwise, try to give a good form that would be valid language + // syntax. Preferably using associated item notation. + + if let Some(trait_ref) = impl_trait_ref { + // Trait impls. + buffer.push(&format!("<{} as {}>", + self_ty, + trait_ref)); + return; + } + + // Inherent impls. Try to print `Foo::bar` for an inherent + // impl on `Foo`, but fallback to `::bar` if self-type is + // anything other than a simple path. + match self_ty.sty { + ty::TyStruct(adt_def, substs) | + ty::TyEnum(adt_def, substs) => { + if substs.types.is_empty() { // ignore regions + self.push_item_path(buffer, adt_def.did); + } else { + buffer.push(&format!("<{}>", self_ty)); + } + } + + ty::TyBool | + ty::TyChar | + ty::TyInt(_) | + ty::TyUint(_) | + ty::TyFloat(_) | + ty::TyStr => { + buffer.push(&format!("{}", self_ty)); + } + + _ => { + buffer.push(&format!("<{}>", self_ty)); + } + } + } + + fn push_impl_path_fallback(&self, + buffer: &mut T, + impl_def_id: DefId) + where T: ItemPathBuffer + { + // If no type info is available, fall back to + // pretty printing some span information. This should + // only occur very early in the compiler pipeline. + let parent_def_id = self.parent_def_id(impl_def_id).unwrap(); + self.push_item_path(buffer, parent_def_id); + let node_id = self.map.as_local_node_id(impl_def_id).unwrap(); + let item = self.map.expect_item(node_id); + let span_str = self.sess.codemap().span_to_string(item.span); + buffer.push(&format!("", span_str)); + } + + /// As a heuristic, when we see an impl, if we see that the + /// 'self-type' is a type defined in the same module as the impl, + /// we can omit including the path to the impl itself. This + /// function tries to find a "characteristic def-id" for a + /// type. It's just a heuristic so it makes some questionable + /// decisions and we may want to adjust it later. + fn characteristic_def_id_of_type(&self, ty: Ty<'tcx>) -> Option { + match ty.sty { + ty::TyStruct(adt_def, _) | + ty::TyEnum(adt_def, _) => + Some(adt_def.did), + + ty::TyTrait(ref data) => + Some(data.principal_def_id()), + + ty::TyBox(subty) => + self.characteristic_def_id_of_type(subty), + + ty::TyRawPtr(mt) | + ty::TyRef(_, mt) => + self.characteristic_def_id_of_type(mt.ty), + + ty::TyTuple(ref tys) => + tys.iter() + .filter_map(|ty| self.characteristic_def_id_of_type(ty)) + .next(), + + _ => + None + } + } + + /// Returns the def-id of `def_id`'s parent in the def tree. If + /// this returns `None`, then `def_id` represents a crate root or + /// inlined root. + fn parent_def_id(&self, def_id: DefId) -> Option { + let key = self.def_key(def_id); + key.parent.map(|index| DefId { krate: def_id.krate, index: index }) + } +} + +/// Unifying Trait for different kinds of item paths we might +/// construct. The basic interface is that components get pushed: the +/// instance can also customize how we handle the root of a crate. +pub trait ItemPathBuffer { + fn root_mode(&self) -> &RootMode; + fn push(&mut self, text: &str); +} + +#[derive(Debug)] +pub enum RootMode { + /// Try to make a path relative to the local crate. In + /// particular, local paths have no prefix, and if the path comes + /// from an extern crate, start with the path to the `extern + /// crate` declaration. + Local, + + /// Always prepend the crate name to the path, forming an absolute + /// path from within a given set of crates. + Absolute, +} + +#[derive(Debug)] +struct LocalPathBuffer { + root_mode: RootMode, + str: String, +} + +impl LocalPathBuffer { + fn new(root_mode: RootMode) -> LocalPathBuffer { + LocalPathBuffer { + root_mode: root_mode, + str: String::new() + } + } + + fn into_string(self) -> String { + self.str + } + +} + +impl ItemPathBuffer for LocalPathBuffer { + fn root_mode(&self) -> &RootMode { + &self.root_mode + } + + fn push(&mut self, text: &str) { + if !self.str.is_empty() { + self.str.push_str("::"); + } + self.str.push_str(text); + } +} diff --git a/src/librustc/ty/ivar.rs b/src/librustc/ty/ivar.rs new file mode 100644 index 00000000000..b0f443fc19b --- /dev/null +++ b/src/librustc/ty/ivar.rs @@ -0,0 +1,87 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use dep_graph::DepNode; +use ty::{Ty, TyS}; +use ty::tls; + +use rustc_data_structures::ivar; + +use std::fmt; +use std::marker::PhantomData; +use core::nonzero::NonZero; + +/// An IVar that contains a Ty. 'lt is a (reverse-variant) upper bound +/// on the lifetime of the IVar. This is required because of variance +/// problems: the IVar needs to be variant with respect to 'tcx (so +/// it can be referred to from Ty) but can only be modified if its +/// lifetime is exactly 'tcx. +/// +/// Safety invariants: +/// (A) self.0, if fulfilled, is a valid Ty<'tcx> +/// (B) no aliases to this value with a 'tcx longer than this +/// value's 'lt exist +/// +/// Dependency tracking: each ivar does not know what node in the +/// dependency graph it is associated with, so when you get/fulfill +/// you must supply a `DepNode` id. This should always be the same id! +/// +/// NonZero is used rather than Unique because Unique isn't Copy. +pub struct TyIVar<'tcx, 'lt: 'tcx>(ivar::Ivar>>, + PhantomData)->TyS<'tcx>>); + +impl<'tcx, 'lt> TyIVar<'tcx, 'lt> { + #[inline] + pub fn new() -> Self { + // Invariant (A) satisfied because the IVar is unfulfilled + // Invariant (B) because 'lt : 'tcx + TyIVar(ivar::Ivar::new(), PhantomData) + } + + #[inline] + pub fn get(&self, dep_node: DepNode) -> Option> { + tls::with(|tcx| tcx.dep_graph.read(dep_node)); + self.untracked_get() + } + + #[inline] + fn untracked_get(&self) -> Option> { + match self.0.get() { + None => None, + // valid because of invariant (A) + Some(v) => Some(unsafe { &*(*v as *const TyS<'tcx>) }) + } + } + + #[inline] + pub fn unwrap(&self, dep_node: DepNode) -> Ty<'tcx> { + self.get(dep_node).unwrap() + } + + pub fn fulfill(&self, dep_node: DepNode, value: Ty<'lt>) { + tls::with(|tcx| tcx.dep_graph.write(dep_node)); + + // Invariant (A) is fulfilled, because by (B), every alias + // of this has a 'tcx longer than 'lt. + let value: *const TyS<'lt> = value; + // FIXME(27214): unneeded [as *const ()] + let value = value as *const () as *const TyS<'static>; + self.0.fulfill(unsafe { NonZero::new(value) }) + } +} + +impl<'tcx, 'lt> fmt::Debug for TyIVar<'tcx, 'lt> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.untracked_get() { + Some(val) => write!(f, "TyIVar({:?})", val), + None => f.write_str("TyIVar()") + } + } +} diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs new file mode 100644 index 00000000000..77b6b03e48f --- /dev/null +++ b/src/librustc/ty/maps.rs @@ -0,0 +1,45 @@ +// Copyright 2012-2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use dep_graph::{DepNode, DepTrackingMapConfig}; +use middle::def_id::DefId; +use ty; +use std::marker::PhantomData; +use std::rc::Rc; +use syntax::{attr, ast}; + +macro_rules! dep_map_ty { + ($ty_name:ident : $node_name:ident ($key:ty) -> $value:ty) => { + pub struct $ty_name<'tcx> { + data: PhantomData<&'tcx ()> + } + + impl<'tcx> DepTrackingMapConfig for $ty_name<'tcx> { + type Key = $key; + type Value = $value; + fn to_dep_node(key: &$key) -> DepNode { DepNode::$node_name(*key) } + } + } +} + +dep_map_ty! { ImplOrTraitItems: ImplOrTraitItems(DefId) -> ty::ImplOrTraitItem<'tcx> } +dep_map_ty! { Tcache: ItemSignature(DefId) -> ty::TypeScheme<'tcx> } +dep_map_ty! { Predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> } +dep_map_ty! { SuperPredicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> } +dep_map_ty! { TraitItemDefIds: TraitItemDefIds(DefId) -> Rc> } +dep_map_ty! { ImplTraitRefs: ItemSignature(DefId) -> Option> } +dep_map_ty! { TraitDefs: ItemSignature(DefId) -> &'tcx ty::TraitDef<'tcx> } +dep_map_ty! { AdtDefs: ItemSignature(DefId) -> ty::AdtDefMaster<'tcx> } +dep_map_ty! { ItemVariances: ItemSignature(DefId) -> Rc } +dep_map_ty! { InherentImpls: InherentImpls(DefId) -> Rc> } +dep_map_ty! { ImplItems: ImplItems(DefId) -> Vec } +dep_map_ty! { TraitItems: TraitItems(DefId) -> Rc>> } +dep_map_ty! { ReprHints: ReprHints(DefId) -> Rc> } +dep_map_ty! { InlinedClosures: Hir(DefId) -> ast::NodeId } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs new file mode 100644 index 00000000000..96a0627c6a4 --- /dev/null +++ b/src/librustc/ty/mod.rs @@ -0,0 +1,2764 @@ +// Copyright 2012-2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use self::ImplOrTraitItemId::*; +pub use self::Variance::*; +pub use self::DtorKind::*; +pub use self::ImplOrTraitItemContainer::*; +pub use self::BorrowKind::*; +pub use self::ImplOrTraitItem::*; +pub use self::IntVarValue::*; +pub use self::LvaluePreference::*; +pub use self::fold::TypeFoldable; + +use dep_graph::{self, DepNode}; +use front::map as ast_map; +use front::map::LinkedPath; +use middle; +use middle::cstore::{self, CrateStore, LOCAL_CRATE}; +use middle::def::{self, Def, ExportMap}; +use middle::def_id::DefId; +use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; +use middle::region::{CodeExtent}; +use traits; +use ty; +use ty::fold::TypeFolder; +use ty::subst::{Subst, Substs, VecPerParamSpace}; +use ty::walk::TypeWalker; +use util::common::MemoizationMap; +use util::nodemap::{NodeMap, NodeSet}; +use util::nodemap::FnvHashMap; + +use serialize::{Encodable, Encoder, Decodable, Decoder}; +use std::borrow::{Borrow, Cow}; +use std::cell::Cell; +use std::hash::{Hash, Hasher}; +use std::iter; +use std::rc::Rc; +use std::slice; +use std::vec::IntoIter; +use std::collections::{HashMap, HashSet}; +use syntax::ast::{self, CrateNum, Name, NodeId}; +use syntax::attr::{self, AttrMetaMethods}; +use syntax::codemap::{DUMMY_SP, Span}; +use syntax::parse::token::InternedString; + +use rustc_const_eval::ConstInt; + +use rustc_front::hir; +use rustc_front::hir::{ItemImpl, ItemTrait, PatKind}; +use rustc_front::intravisit::Visitor; + +pub use self::sty::{Binder, DebruijnIndex}; +pub use self::sty::{BuiltinBound, BuiltinBounds, ExistentialBounds}; +pub use self::sty::{BareFnTy, FnSig, PolyFnSig, FnOutput, PolyFnOutput}; +pub use self::sty::{ClosureTy, InferTy, ParamTy, ProjectionTy, TraitTy}; +pub use self::sty::{ClosureSubsts, TypeAndMut}; +pub use self::sty::{TraitRef, TypeVariants, PolyTraitRef}; +pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region}; +pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid, SkolemizedRegionVid}; +pub use self::sty::BoundRegion::*; +pub use self::sty::FnOutput::*; +pub use self::sty::InferTy::*; +pub use self::sty::Region::*; +pub use self::sty::TypeVariants::*; + +pub use self::sty::BuiltinBound::Send as BoundSend; +pub use self::sty::BuiltinBound::Sized as BoundSized; +pub use self::sty::BuiltinBound::Copy as BoundCopy; +pub use self::sty::BuiltinBound::Sync as BoundSync; + +pub use self::contents::TypeContents; +pub use self::context::{TyCtxt, tls}; +pub use self::context::{CtxtArenas, Lift, Tables}; + +pub use self::trait_def::{TraitDef, TraitFlags}; + +pub mod adjustment; +pub mod cast; +pub mod error; +pub mod fast_reject; +pub mod fold; +pub mod item_path; +pub mod _match; +pub mod maps; +pub mod outlives; +pub mod relate; +pub mod subst; +pub mod trait_def; +pub mod walk; +pub mod wf; +pub mod util; + +mod contents; +mod context; +mod flags; +mod ivar; +mod structural_impls; +mod sty; + +pub type Disr = ConstInt; + +// Data types + +/// The complete set of all analyses described in this module. This is +/// produced by the driver and fed to trans and later passes. +pub struct CrateAnalysis<'a> { + pub export_map: ExportMap, + pub access_levels: middle::privacy::AccessLevels, + pub reachable: NodeSet, + pub name: &'a str, + pub glob_map: Option, +} + +#[derive(Copy, Clone)] +pub enum DtorKind { + NoDtor, + TraitDtor(bool) +} + +impl DtorKind { + pub fn is_present(&self) -> bool { + match *self { + TraitDtor(..) => true, + _ => false + } + } + + pub fn has_drop_flag(&self) -> bool { + match self { + &NoDtor => false, + &TraitDtor(flag) => flag + } + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum ImplOrTraitItemContainer { + TraitContainer(DefId), + ImplContainer(DefId), +} + +impl ImplOrTraitItemContainer { + pub fn id(&self) -> DefId { + match *self { + TraitContainer(id) => id, + ImplContainer(id) => id, + } + } +} + +/// The "header" of an impl is everything outside the body: a Self type, a trait +/// ref (in the case of a trait impl), and a set of predicates (from the +/// bounds/where clauses). +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct ImplHeader<'tcx> { + pub impl_def_id: DefId, + pub self_ty: Ty<'tcx>, + pub trait_ref: Option>, + pub predicates: Vec>, +} + +impl<'tcx> ImplHeader<'tcx> { + pub fn with_fresh_ty_vars<'a>(selcx: &mut traits::SelectionContext<'a, 'tcx>, + impl_def_id: DefId) + -> ImplHeader<'tcx> + { + let tcx = selcx.tcx(); + let impl_generics = tcx.lookup_item_type(impl_def_id).generics; + let impl_substs = selcx.infcx().fresh_substs_for_generics(DUMMY_SP, &impl_generics); + + let header = ImplHeader { + impl_def_id: impl_def_id, + self_ty: tcx.lookup_item_type(impl_def_id).ty, + trait_ref: tcx.impl_trait_ref(impl_def_id), + predicates: tcx.lookup_predicates(impl_def_id).predicates.into_vec(), + }.subst(tcx, &impl_substs); + + let traits::Normalized { value: mut header, obligations } = + traits::normalize(selcx, traits::ObligationCause::dummy(), &header); + + header.predicates.extend(obligations.into_iter().map(|o| o.predicate)); + header + } +} + +#[derive(Clone)] +pub enum ImplOrTraitItem<'tcx> { + ConstTraitItem(Rc>), + MethodTraitItem(Rc>), + TypeTraitItem(Rc>), +} + +impl<'tcx> ImplOrTraitItem<'tcx> { + fn id(&self) -> ImplOrTraitItemId { + match *self { + ConstTraitItem(ref associated_const) => { + ConstTraitItemId(associated_const.def_id) + } + MethodTraitItem(ref method) => MethodTraitItemId(method.def_id), + TypeTraitItem(ref associated_type) => { + TypeTraitItemId(associated_type.def_id) + } + } + } + + pub fn def(&self) -> Def { + match *self { + ConstTraitItem(ref associated_const) => Def::AssociatedConst(associated_const.def_id), + MethodTraitItem(ref method) => Def::Method(method.def_id), + TypeTraitItem(ref ty) => Def::AssociatedTy(ty.container.id(), ty.def_id), + } + } + + pub fn def_id(&self) -> DefId { + match *self { + ConstTraitItem(ref associated_const) => associated_const.def_id, + MethodTraitItem(ref method) => method.def_id, + TypeTraitItem(ref associated_type) => associated_type.def_id, + } + } + + pub fn name(&self) -> Name { + match *self { + ConstTraitItem(ref associated_const) => associated_const.name, + MethodTraitItem(ref method) => method.name, + TypeTraitItem(ref associated_type) => associated_type.name, + } + } + + pub fn vis(&self) -> hir::Visibility { + match *self { + ConstTraitItem(ref associated_const) => associated_const.vis, + MethodTraitItem(ref method) => method.vis, + TypeTraitItem(ref associated_type) => associated_type.vis, + } + } + + pub fn container(&self) -> ImplOrTraitItemContainer { + match *self { + ConstTraitItem(ref associated_const) => associated_const.container, + MethodTraitItem(ref method) => method.container, + TypeTraitItem(ref associated_type) => associated_type.container, + } + } + + pub fn as_opt_method(&self) -> Option>> { + match *self { + MethodTraitItem(ref m) => Some((*m).clone()), + _ => None, + } + } +} + +#[derive(Clone, Copy, Debug)] +pub enum ImplOrTraitItemId { + ConstTraitItemId(DefId), + MethodTraitItemId(DefId), + TypeTraitItemId(DefId), +} + +impl ImplOrTraitItemId { + pub fn def_id(&self) -> DefId { + match *self { + ConstTraitItemId(def_id) => def_id, + MethodTraitItemId(def_id) => def_id, + TypeTraitItemId(def_id) => def_id, + } + } +} + +#[derive(Clone, Debug)] +pub struct Method<'tcx> { + pub name: Name, + pub generics: Generics<'tcx>, + pub predicates: GenericPredicates<'tcx>, + pub fty: BareFnTy<'tcx>, + pub explicit_self: ExplicitSelfCategory, + pub vis: hir::Visibility, + pub defaultness: hir::Defaultness, + pub def_id: DefId, + pub container: ImplOrTraitItemContainer, +} + +impl<'tcx> Method<'tcx> { + pub fn new(name: Name, + generics: ty::Generics<'tcx>, + predicates: GenericPredicates<'tcx>, + fty: BareFnTy<'tcx>, + explicit_self: ExplicitSelfCategory, + vis: hir::Visibility, + defaultness: hir::Defaultness, + def_id: DefId, + container: ImplOrTraitItemContainer) + -> Method<'tcx> { + Method { + name: name, + generics: generics, + predicates: predicates, + fty: fty, + explicit_self: explicit_self, + vis: vis, + defaultness: defaultness, + def_id: def_id, + container: container, + } + } + + pub fn container_id(&self) -> DefId { + match self.container { + TraitContainer(id) => id, + ImplContainer(id) => id, + } + } +} + +impl<'tcx> PartialEq for Method<'tcx> { + #[inline] + fn eq(&self, other: &Self) -> bool { self.def_id == other.def_id } +} + +impl<'tcx> Eq for Method<'tcx> {} + +impl<'tcx> Hash for Method<'tcx> { + #[inline] + fn hash(&self, s: &mut H) { + self.def_id.hash(s) + } +} + +#[derive(Clone, Copy, Debug)] +pub struct AssociatedConst<'tcx> { + pub name: Name, + pub ty: Ty<'tcx>, + pub vis: hir::Visibility, + pub defaultness: hir::Defaultness, + pub def_id: DefId, + pub container: ImplOrTraitItemContainer, + pub has_value: bool +} + +#[derive(Clone, Copy, Debug)] +pub struct AssociatedType<'tcx> { + pub name: Name, + pub ty: Option>, + pub vis: hir::Visibility, + pub defaultness: hir::Defaultness, + pub def_id: DefId, + pub container: ImplOrTraitItemContainer, +} + +#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)] +pub struct ItemVariances { + pub types: VecPerParamSpace, + pub regions: VecPerParamSpace, +} + +#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Copy)] +pub enum Variance { + Covariant, // T <: T iff A <: B -- e.g., function return type + Invariant, // T <: T iff B == A -- e.g., type of mutable cell + Contravariant, // T <: T iff B <: A -- e.g., function param type + Bivariant, // T <: T -- e.g., unused type parameter +} + +#[derive(Clone, Copy, Debug)] +pub struct MethodCallee<'tcx> { + /// Impl method ID, for inherent methods, or trait method ID, otherwise. + pub def_id: DefId, + pub ty: Ty<'tcx>, + pub substs: &'tcx subst::Substs<'tcx> +} + +/// With method calls, we store some extra information in +/// side tables (i.e method_map). We use +/// MethodCall as a key to index into these tables instead of +/// just directly using the expression's NodeId. The reason +/// for this being that we may apply adjustments (coercions) +/// with the resulting expression also needing to use the +/// side tables. The problem with this is that we don't +/// assign a separate NodeId to this new expression +/// and so it would clash with the base expression if both +/// needed to add to the side tables. Thus to disambiguate +/// we also keep track of whether there's an adjustment in +/// our key. +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub struct MethodCall { + pub expr_id: NodeId, + pub autoderef: u32 +} + +impl MethodCall { + pub fn expr(id: NodeId) -> MethodCall { + MethodCall { + expr_id: id, + autoderef: 0 + } + } + + pub fn autoderef(expr_id: NodeId, autoderef: u32) -> MethodCall { + MethodCall { + expr_id: expr_id, + autoderef: 1 + autoderef + } + } +} + +// maps from an expression id that corresponds to a method call to the details +// of the method to be invoked +pub type MethodMap<'tcx> = FnvHashMap>; + +// Contains information needed to resolve types and (in the future) look up +// the types of AST nodes. +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct CReaderCacheKey { + pub cnum: CrateNum, + pub pos: usize, +} + +/// A restriction that certain types must be the same size. The use of +/// `transmute` gives rise to these restrictions. These generally +/// cannot be checked until trans; therefore, each call to `transmute` +/// will push one or more such restriction into the +/// `transmute_restrictions` vector during `intrinsicck`. They are +/// then checked during `trans` by the fn `check_intrinsics`. +#[derive(Copy, Clone)] +pub struct TransmuteRestriction<'tcx> { + /// The span whence the restriction comes. + pub span: Span, + + /// The type being transmuted from. + pub original_from: Ty<'tcx>, + + /// The type being transmuted to. + pub original_to: Ty<'tcx>, + + /// The type being transmuted from, with all type parameters + /// substituted for an arbitrary representative. Not to be shown + /// to the end user. + pub substituted_from: Ty<'tcx>, + + /// The type being transmuted to, with all type parameters + /// substituted for an arbitrary representative. Not to be shown + /// to the end user. + pub substituted_to: Ty<'tcx>, + + /// NodeId of the transmute intrinsic. + pub id: NodeId, +} + +/// Describes the fragment-state associated with a NodeId. +/// +/// Currently only unfragmented paths have entries in the table, +/// but longer-term this enum is expected to expand to also +/// include data for fragmented paths. +#[derive(Copy, Clone, Debug)] +pub enum FragmentInfo { + Moved { var: NodeId, move_expr: NodeId }, + Assigned { var: NodeId, assign_expr: NodeId, assignee_id: NodeId }, +} + +// Flags that we track on types. These flags are propagated upwards +// through the type during type construction, so that we can quickly +// check whether the type has various kinds of types in it without +// recursing over the type itself. +bitflags! { + flags TypeFlags: u32 { + const HAS_PARAMS = 1 << 0, + const HAS_SELF = 1 << 1, + const HAS_TY_INFER = 1 << 2, + const HAS_RE_INFER = 1 << 3, + const HAS_RE_EARLY_BOUND = 1 << 4, + const HAS_FREE_REGIONS = 1 << 5, + const HAS_TY_ERR = 1 << 6, + const HAS_PROJECTION = 1 << 7, + const HAS_TY_CLOSURE = 1 << 8, + + // true if there are "names" of types and regions and so forth + // that are local to a particular fn + const HAS_LOCAL_NAMES = 1 << 9, + + const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits | + TypeFlags::HAS_SELF.bits | + TypeFlags::HAS_RE_EARLY_BOUND.bits, + + // Flags representing the nominal content of a type, + // computed by FlagsComputation. If you add a new nominal + // flag, it should be added here too. + const NOMINAL_FLAGS = TypeFlags::HAS_PARAMS.bits | + TypeFlags::HAS_SELF.bits | + TypeFlags::HAS_TY_INFER.bits | + TypeFlags::HAS_RE_INFER.bits | + TypeFlags::HAS_RE_EARLY_BOUND.bits | + TypeFlags::HAS_FREE_REGIONS.bits | + TypeFlags::HAS_TY_ERR.bits | + TypeFlags::HAS_PROJECTION.bits | + TypeFlags::HAS_TY_CLOSURE.bits | + TypeFlags::HAS_LOCAL_NAMES.bits, + + // Caches for type_is_sized, type_moves_by_default + const SIZEDNESS_CACHED = 1 << 16, + const IS_SIZED = 1 << 17, + const MOVENESS_CACHED = 1 << 18, + const MOVES_BY_DEFAULT = 1 << 19, + } +} + +pub struct TyS<'tcx> { + pub sty: TypeVariants<'tcx>, + pub flags: Cell, + + // the maximal depth of any bound regions appearing in this type. + region_depth: u32, +} + +impl<'tcx> PartialEq for TyS<'tcx> { + #[inline] + fn eq(&self, other: &TyS<'tcx>) -> bool { + // (self as *const _) == (other as *const _) + (self as *const TyS<'tcx>) == (other as *const TyS<'tcx>) + } +} +impl<'tcx> Eq for TyS<'tcx> {} + +impl<'tcx> Hash for TyS<'tcx> { + fn hash(&self, s: &mut H) { + (self as *const TyS).hash(s) + } +} + +pub type Ty<'tcx> = &'tcx TyS<'tcx>; + +impl<'tcx> Encodable for Ty<'tcx> { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + cstore::tls::with_encoding_context(s, |ecx, rbml_w| { + ecx.encode_ty(rbml_w, *self); + Ok(()) + }) + } +} + +impl<'tcx> Decodable for Ty<'tcx> { + fn decode(d: &mut D) -> Result, D::Error> { + cstore::tls::with_decoding_context(d, |dcx, rbml_r| { + Ok(dcx.decode_ty(rbml_r)) + }) + } +} + + +/// Upvars do not get their own node-id. Instead, we use the pair of +/// the original var id (that is, the root variable that is referenced +/// by the upvar) and the id of the closure expression. +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct UpvarId { + pub var_id: NodeId, + pub closure_expr_id: NodeId, +} + +#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable, Copy)] +pub enum BorrowKind { + /// Data must be immutable and is aliasable. + ImmBorrow, + + /// Data must be immutable but not aliasable. This kind of borrow + /// cannot currently be expressed by the user and is used only in + /// implicit closure bindings. It is needed when you the closure + /// is borrowing or mutating a mutable referent, e.g.: + /// + /// let x: &mut isize = ...; + /// let y = || *x += 5; + /// + /// If we were to try to translate this closure into a more explicit + /// form, we'd encounter an error with the code as written: + /// + /// struct Env { x: & &mut isize } + /// let x: &mut isize = ...; + /// let y = (&mut Env { &x }, fn_ptr); // Closure is pair of env and fn + /// fn fn_ptr(env: &mut Env) { **env.x += 5; } + /// + /// This is then illegal because you cannot mutate a `&mut` found + /// in an aliasable location. To solve, you'd have to translate with + /// an `&mut` borrow: + /// + /// struct Env { x: & &mut isize } + /// let x: &mut isize = ...; + /// let y = (&mut Env { &mut x }, fn_ptr); // changed from &x to &mut x + /// fn fn_ptr(env: &mut Env) { **env.x += 5; } + /// + /// Now the assignment to `**env.x` is legal, but creating a + /// mutable pointer to `x` is not because `x` is not mutable. We + /// could fix this by declaring `x` as `let mut x`. This is ok in + /// user code, if awkward, but extra weird for closures, since the + /// borrow is hidden. + /// + /// So we introduce a "unique imm" borrow -- the referent is + /// immutable, but not aliasable. This solves the problem. For + /// simplicity, we don't give users the way to express this + /// borrow, it's just used when translating closures. + UniqueImmBorrow, + + /// Data is mutable and not aliasable. + MutBorrow +} + +/// Information describing the capture of an upvar. This is computed +/// during `typeck`, specifically by `regionck`. +#[derive(PartialEq, Clone, Debug, Copy)] +pub enum UpvarCapture { + /// Upvar is captured by value. This is always true when the + /// closure is labeled `move`, but can also be true in other cases + /// depending on inference. + ByValue, + + /// Upvar is captured by reference. + ByRef(UpvarBorrow), +} + +#[derive(PartialEq, Clone, Copy)] +pub struct UpvarBorrow { + /// The kind of borrow: by-ref upvars have access to shared + /// immutable borrows, which are not part of the normal language + /// syntax. + pub kind: BorrowKind, + + /// Region of the resulting reference. + pub region: ty::Region, +} + +pub type UpvarCaptureMap = FnvHashMap; + +#[derive(Copy, Clone)] +pub struct ClosureUpvar<'tcx> { + pub def: Def, + pub span: Span, + pub ty: Ty<'tcx>, +} + +#[derive(Clone, Copy, PartialEq)] +pub enum IntVarValue { + IntType(ast::IntTy), + UintType(ast::UintTy), +} + +/// Default region to use for the bound of objects that are +/// supplied as the value for this type parameter. This is derived +/// from `T:'a` annotations appearing in the type definition. If +/// this is `None`, then the default is inherited from the +/// surrounding context. See RFC #599 for details. +#[derive(Copy, Clone)] +pub enum ObjectLifetimeDefault { + /// Require an explicit annotation. Occurs when multiple + /// `T:'a` constraints are found. + Ambiguous, + + /// Use the base default, typically 'static, but in a fn body it is a fresh variable + BaseDefault, + + /// Use the given region as the default. + Specific(Region), +} + +#[derive(Clone)] +pub struct TypeParameterDef<'tcx> { + pub name: Name, + pub def_id: DefId, + pub space: subst::ParamSpace, + pub index: u32, + pub default_def_id: DefId, // for use in error reporing about defaults + pub default: Option>, + pub object_lifetime_default: ObjectLifetimeDefault, +} + +#[derive(Clone)] +pub struct RegionParameterDef { + pub name: Name, + pub def_id: DefId, + pub space: subst::ParamSpace, + pub index: u32, + pub bounds: Vec, +} + +impl RegionParameterDef { + pub fn to_early_bound_region(&self) -> ty::Region { + ty::ReEarlyBound(ty::EarlyBoundRegion { + space: self.space, + index: self.index, + name: self.name, + }) + } + pub fn to_bound_region(&self) -> ty::BoundRegion { + ty::BoundRegion::BrNamed(self.def_id, self.name) + } +} + +/// Information about the formal type/lifetime parameters associated +/// with an item or method. Analogous to hir::Generics. +#[derive(Clone, Debug)] +pub struct Generics<'tcx> { + pub types: VecPerParamSpace>, + pub regions: VecPerParamSpace, +} + +impl<'tcx> Generics<'tcx> { + pub fn empty() -> Generics<'tcx> { + Generics { + types: VecPerParamSpace::empty(), + regions: VecPerParamSpace::empty(), + } + } + + pub fn is_empty(&self) -> bool { + self.types.is_empty() && self.regions.is_empty() + } + + pub fn has_type_params(&self, space: subst::ParamSpace) -> bool { + !self.types.is_empty_in(space) + } + + pub fn has_region_params(&self, space: subst::ParamSpace) -> bool { + !self.regions.is_empty_in(space) + } +} + +/// Bounds on generics. +#[derive(Clone)] +pub struct GenericPredicates<'tcx> { + pub predicates: VecPerParamSpace>, +} + +impl<'tcx> GenericPredicates<'tcx> { + pub fn empty() -> GenericPredicates<'tcx> { + GenericPredicates { + predicates: VecPerParamSpace::empty(), + } + } + + pub fn instantiate(&self, tcx: &TyCtxt<'tcx>, substs: &Substs<'tcx>) + -> InstantiatedPredicates<'tcx> { + InstantiatedPredicates { + predicates: self.predicates.subst(tcx, substs), + } + } + + pub fn instantiate_supertrait(&self, + tcx: &TyCtxt<'tcx>, + poly_trait_ref: &ty::PolyTraitRef<'tcx>) + -> InstantiatedPredicates<'tcx> + { + InstantiatedPredicates { + predicates: self.predicates.map(|pred| pred.subst_supertrait(tcx, poly_trait_ref)) + } + } +} + +#[derive(Clone, PartialEq, Eq, Hash)] +pub enum Predicate<'tcx> { + /// Corresponds to `where Foo : Bar`. `Foo` here would be + /// the `Self` type of the trait reference and `A`, `B`, and `C` + /// would be the parameters in the `TypeSpace`. + Trait(PolyTraitPredicate<'tcx>), + + /// where `T1 == T2`. + Equate(PolyEquatePredicate<'tcx>), + + /// where 'a : 'b + RegionOutlives(PolyRegionOutlivesPredicate), + + /// where T : 'a + TypeOutlives(PolyTypeOutlivesPredicate<'tcx>), + + /// where ::Name == X, approximately. + /// See `ProjectionPredicate` struct for details. + Projection(PolyProjectionPredicate<'tcx>), + + /// no syntax: T WF + WellFormed(Ty<'tcx>), + + /// trait must be object-safe + ObjectSafe(DefId), +} + +impl<'tcx> Predicate<'tcx> { + /// Performs a substitution suitable for going from a + /// poly-trait-ref to supertraits that must hold if that + /// poly-trait-ref holds. This is slightly different from a normal + /// substitution in terms of what happens with bound regions. See + /// lengthy comment below for details. + pub fn subst_supertrait(&self, + tcx: &TyCtxt<'tcx>, + trait_ref: &ty::PolyTraitRef<'tcx>) + -> ty::Predicate<'tcx> + { + // The interaction between HRTB and supertraits is not entirely + // obvious. Let me walk you (and myself) through an example. + // + // Let's start with an easy case. Consider two traits: + // + // trait Foo<'a> : Bar<'a,'a> { } + // trait Bar<'b,'c> { } + // + // Now, if we have a trait reference `for<'x> T : Foo<'x>`, then + // we can deduce that `for<'x> T : Bar<'x,'x>`. Basically, if we + // knew that `Foo<'x>` (for any 'x) then we also know that + // `Bar<'x,'x>` (for any 'x). This more-or-less falls out from + // normal substitution. + // + // In terms of why this is sound, the idea is that whenever there + // is an impl of `T:Foo<'a>`, it must show that `T:Bar<'a,'a>` + // holds. So if there is an impl of `T:Foo<'a>` that applies to + // all `'a`, then we must know that `T:Bar<'a,'a>` holds for all + // `'a`. + // + // Another example to be careful of is this: + // + // trait Foo1<'a> : for<'b> Bar1<'a,'b> { } + // trait Bar1<'b,'c> { } + // + // Here, if we have `for<'x> T : Foo1<'x>`, then what do we know? + // The answer is that we know `for<'x,'b> T : Bar1<'x,'b>`. The + // reason is similar to the previous example: any impl of + // `T:Foo1<'x>` must show that `for<'b> T : Bar1<'x, 'b>`. So + // basically we would want to collapse the bound lifetimes from + // the input (`trait_ref`) and the supertraits. + // + // To achieve this in practice is fairly straightforward. Let's + // consider the more complicated scenario: + // + // - We start out with `for<'x> T : Foo1<'x>`. In this case, `'x` + // has a De Bruijn index of 1. We want to produce `for<'x,'b> T : Bar1<'x,'b>`, + // where both `'x` and `'b` would have a DB index of 1. + // The substitution from the input trait-ref is therefore going to be + // `'a => 'x` (where `'x` has a DB index of 1). + // - The super-trait-ref is `for<'b> Bar1<'a,'b>`, where `'a` is an + // early-bound parameter and `'b' is a late-bound parameter with a + // DB index of 1. + // - If we replace `'a` with `'x` from the input, it too will have + // a DB index of 1, and thus we'll have `for<'x,'b> Bar1<'x,'b>` + // just as we wanted. + // + // There is only one catch. If we just apply the substitution `'a + // => 'x` to `for<'b> Bar1<'a,'b>`, the substitution code will + // adjust the DB index because we substituting into a binder (it + // tries to be so smart...) resulting in `for<'x> for<'b> + // Bar1<'x,'b>` (we have no syntax for this, so use your + // imagination). Basically the 'x will have DB index of 2 and 'b + // will have DB index of 1. Not quite what we want. So we apply + // the substitution to the *contents* of the trait reference, + // rather than the trait reference itself (put another way, the + // substitution code expects equal binding levels in the values + // from the substitution and the value being substituted into, and + // this trick achieves that). + + let substs = &trait_ref.0.substs; + match *self { + Predicate::Trait(ty::Binder(ref data)) => + Predicate::Trait(ty::Binder(data.subst(tcx, substs))), + Predicate::Equate(ty::Binder(ref data)) => + Predicate::Equate(ty::Binder(data.subst(tcx, substs))), + Predicate::RegionOutlives(ty::Binder(ref data)) => + Predicate::RegionOutlives(ty::Binder(data.subst(tcx, substs))), + Predicate::TypeOutlives(ty::Binder(ref data)) => + Predicate::TypeOutlives(ty::Binder(data.subst(tcx, substs))), + Predicate::Projection(ty::Binder(ref data)) => + Predicate::Projection(ty::Binder(data.subst(tcx, substs))), + Predicate::WellFormed(data) => + Predicate::WellFormed(data.subst(tcx, substs)), + Predicate::ObjectSafe(trait_def_id) => + Predicate::ObjectSafe(trait_def_id), + } + } +} + +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct TraitPredicate<'tcx> { + pub trait_ref: TraitRef<'tcx> +} +pub type PolyTraitPredicate<'tcx> = ty::Binder>; + +impl<'tcx> TraitPredicate<'tcx> { + pub fn def_id(&self) -> DefId { + self.trait_ref.def_id + } + + /// Creates the dep-node for selecting/evaluating this trait reference. + fn dep_node(&self) -> DepNode { + DepNode::TraitSelect(self.def_id()) + } + + pub fn input_types(&self) -> &[Ty<'tcx>] { + self.trait_ref.substs.types.as_slice() + } + + pub fn self_ty(&self) -> Ty<'tcx> { + self.trait_ref.self_ty() + } +} + +impl<'tcx> PolyTraitPredicate<'tcx> { + pub fn def_id(&self) -> DefId { + // ok to skip binder since trait def-id does not care about regions + self.0.def_id() + } + + pub fn dep_node(&self) -> DepNode { + // ok to skip binder since depnode does not care about regions + self.0.dep_node() + } +} + +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct EquatePredicate<'tcx>(pub Ty<'tcx>, pub Ty<'tcx>); // `0 == 1` +pub type PolyEquatePredicate<'tcx> = ty::Binder>; + +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct OutlivesPredicate(pub A, pub B); // `A : B` +pub type PolyOutlivesPredicate = ty::Binder>; +pub type PolyRegionOutlivesPredicate = PolyOutlivesPredicate; +pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate, ty::Region>; + +/// This kind of predicate has no *direct* correspondent in the +/// syntax, but it roughly corresponds to the syntactic forms: +/// +/// 1. `T : TraitRef<..., Item=Type>` +/// 2. `>::Item == Type` (NYI) +/// +/// In particular, form #1 is "desugared" to the combination of a +/// normal trait predicate (`T : TraitRef<...>`) and one of these +/// predicates. Form #2 is a broader form in that it also permits +/// equality between arbitrary types. Processing an instance of Form +/// #2 eventually yields one of these `ProjectionPredicate` +/// instances to normalize the LHS. +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct ProjectionPredicate<'tcx> { + pub projection_ty: ProjectionTy<'tcx>, + pub ty: Ty<'tcx>, +} + +pub type PolyProjectionPredicate<'tcx> = Binder>; + +impl<'tcx> PolyProjectionPredicate<'tcx> { + pub fn item_name(&self) -> Name { + self.0.projection_ty.item_name // safe to skip the binder to access a name + } + + pub fn sort_key(&self) -> (DefId, Name) { + self.0.projection_ty.sort_key() + } +} + +pub trait ToPolyTraitRef<'tcx> { + fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>; +} + +impl<'tcx> ToPolyTraitRef<'tcx> for TraitRef<'tcx> { + fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { + assert!(!self.has_escaping_regions()); + ty::Binder(self.clone()) + } +} + +impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> { + fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { + self.map_bound_ref(|trait_pred| trait_pred.trait_ref) + } +} + +impl<'tcx> ToPolyTraitRef<'tcx> for PolyProjectionPredicate<'tcx> { + fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { + // Note: unlike with TraitRef::to_poly_trait_ref(), + // self.0.trait_ref is permitted to have escaping regions. + // This is because here `self` has a `Binder` and so does our + // return value, so we are preserving the number of binding + // levels. + ty::Binder(self.0.projection_ty.trait_ref) + } +} + +pub trait ToPredicate<'tcx> { + fn to_predicate(&self) -> Predicate<'tcx>; +} + +impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> { + fn to_predicate(&self) -> Predicate<'tcx> { + // we're about to add a binder, so let's check that we don't + // accidentally capture anything, or else that might be some + // weird debruijn accounting. + assert!(!self.has_escaping_regions()); + + ty::Predicate::Trait(ty::Binder(ty::TraitPredicate { + trait_ref: self.clone() + })) + } +} + +impl<'tcx> ToPredicate<'tcx> for PolyTraitRef<'tcx> { + fn to_predicate(&self) -> Predicate<'tcx> { + ty::Predicate::Trait(self.to_poly_trait_predicate()) + } +} + +impl<'tcx> ToPredicate<'tcx> for PolyEquatePredicate<'tcx> { + fn to_predicate(&self) -> Predicate<'tcx> { + Predicate::Equate(self.clone()) + } +} + +impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate { + fn to_predicate(&self) -> Predicate<'tcx> { + Predicate::RegionOutlives(self.clone()) + } +} + +impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> { + fn to_predicate(&self) -> Predicate<'tcx> { + Predicate::TypeOutlives(self.clone()) + } +} + +impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { + fn to_predicate(&self) -> Predicate<'tcx> { + Predicate::Projection(self.clone()) + } +} + +impl<'tcx> Predicate<'tcx> { + /// Iterates over the types in this predicate. Note that in all + /// cases this is skipping over a binder, so late-bound regions + /// with depth 0 are bound by the predicate. + pub fn walk_tys(&self) -> IntoIter> { + let vec: Vec<_> = match *self { + ty::Predicate::Trait(ref data) => { + data.0.trait_ref.substs.types.as_slice().to_vec() + } + ty::Predicate::Equate(ty::Binder(ref data)) => { + vec![data.0, data.1] + } + ty::Predicate::TypeOutlives(ty::Binder(ref data)) => { + vec![data.0] + } + ty::Predicate::RegionOutlives(..) => { + vec![] + } + ty::Predicate::Projection(ref data) => { + let trait_inputs = data.0.projection_ty.trait_ref.substs.types.as_slice(); + trait_inputs.iter() + .cloned() + .chain(Some(data.0.ty)) + .collect() + } + ty::Predicate::WellFormed(data) => { + vec![data] + } + ty::Predicate::ObjectSafe(_trait_def_id) => { + vec![] + } + }; + + // The only reason to collect into a vector here is that I was + // too lazy to make the full (somewhat complicated) iterator + // type that would be needed here. But I wanted this fn to + // return an iterator conceptually, rather than a `Vec`, so as + // to be closer to `Ty::walk`. + vec.into_iter() + } + + pub fn to_opt_poly_trait_ref(&self) -> Option> { + match *self { + Predicate::Trait(ref t) => { + Some(t.to_poly_trait_ref()) + } + Predicate::Projection(..) | + Predicate::Equate(..) | + Predicate::RegionOutlives(..) | + Predicate::WellFormed(..) | + Predicate::ObjectSafe(..) | + Predicate::TypeOutlives(..) => { + None + } + } + } +} + +/// Represents the bounds declared on a particular set of type +/// parameters. Should eventually be generalized into a flag list of +/// where clauses. You can obtain a `InstantiatedPredicates` list from a +/// `GenericPredicates` by using the `instantiate` method. Note that this method +/// reflects an important semantic invariant of `InstantiatedPredicates`: while +/// the `GenericPredicates` are expressed in terms of the bound type +/// parameters of the impl/trait/whatever, an `InstantiatedPredicates` instance +/// represented a set of bounds for some particular instantiation, +/// meaning that the generic parameters have been substituted with +/// their values. +/// +/// Example: +/// +/// struct Foo> { ... } +/// +/// Here, the `GenericPredicates` for `Foo` would contain a list of bounds like +/// `[[], [U:Bar]]`. Now if there were some particular reference +/// like `Foo`, then the `InstantiatedPredicates` would be `[[], +/// [usize:Bar]]`. +#[derive(Clone)] +pub struct InstantiatedPredicates<'tcx> { + pub predicates: VecPerParamSpace>, +} + +impl<'tcx> InstantiatedPredicates<'tcx> { + pub fn empty() -> InstantiatedPredicates<'tcx> { + InstantiatedPredicates { predicates: VecPerParamSpace::empty() } + } + + pub fn is_empty(&self) -> bool { + self.predicates.is_empty() + } +} + +impl<'tcx> TraitRef<'tcx> { + pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>) -> TraitRef<'tcx> { + TraitRef { def_id: def_id, substs: substs } + } + + pub fn self_ty(&self) -> Ty<'tcx> { + self.substs.self_ty().unwrap() + } + + pub fn input_types(&self) -> &[Ty<'tcx>] { + // Select only the "input types" from a trait-reference. For + // now this is all the types that appear in the + // trait-reference, but it should eventually exclude + // associated types. + self.substs.types.as_slice() + } +} + +/// When type checking, we use the `ParameterEnvironment` to track +/// details about the type/lifetime parameters that are in scope. +/// It primarily stores the bounds information. +/// +/// Note: This information might seem to be redundant with the data in +/// `tcx.ty_param_defs`, but it is not. That table contains the +/// parameter definitions from an "outside" perspective, but this +/// struct will contain the bounds for a parameter as seen from inside +/// the function body. Currently the only real distinction is that +/// bound lifetime parameters are replaced with free ones, but in the +/// future I hope to refine the representation of types so as to make +/// more distinctions clearer. +#[derive(Clone)] +pub struct ParameterEnvironment<'a, 'tcx:'a> { + pub tcx: &'a TyCtxt<'tcx>, + + /// See `construct_free_substs` for details. + pub free_substs: Substs<'tcx>, + + /// Each type parameter has an implicit region bound that + /// indicates it must outlive at least the function body (the user + /// may specify stronger requirements). This field indicates the + /// region of the callee. + pub implicit_region_bound: ty::Region, + + /// Obligations that the caller must satisfy. This is basically + /// the set of bounds on the in-scope type parameters, translated + /// into Obligations, and elaborated and normalized. + pub caller_bounds: Vec>, + + /// Caches the results of trait selection. This cache is used + /// for things that have to do with the parameters in scope. + pub selection_cache: traits::SelectionCache<'tcx>, + + /// Caches the results of trait evaluation. + pub evaluation_cache: traits::EvaluationCache<'tcx>, + + /// Scope that is attached to free regions for this scope. This + /// is usually the id of the fn body, but for more abstract scopes + /// like structs we often use the node-id of the struct. + /// + /// FIXME(#3696). It would be nice to refactor so that free + /// regions don't have this implicit scope and instead introduce + /// relationships in the environment. + pub free_id_outlive: CodeExtent, +} + +impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { + pub fn with_caller_bounds(&self, + caller_bounds: Vec>) + -> ParameterEnvironment<'a,'tcx> + { + ParameterEnvironment { + tcx: self.tcx, + free_substs: self.free_substs.clone(), + implicit_region_bound: self.implicit_region_bound, + caller_bounds: caller_bounds, + selection_cache: traits::SelectionCache::new(), + evaluation_cache: traits::EvaluationCache::new(), + free_id_outlive: self.free_id_outlive, + } + } + + pub fn for_item(cx: &'a TyCtxt<'tcx>, id: NodeId) -> ParameterEnvironment<'a, 'tcx> { + match cx.map.find(id) { + Some(ast_map::NodeImplItem(ref impl_item)) => { + match impl_item.node { + hir::ImplItemKind::Type(_) => { + // associated types don't have their own entry (for some reason), + // so for now just grab environment for the impl + let impl_id = cx.map.get_parent(id); + let impl_def_id = cx.map.local_def_id(impl_id); + let scheme = cx.lookup_item_type(impl_def_id); + let predicates = cx.lookup_predicates(impl_def_id); + cx.construct_parameter_environment(impl_item.span, + &scheme.generics, + &predicates, + cx.region_maps.item_extent(id)) + } + hir::ImplItemKind::Const(_, _) => { + let def_id = cx.map.local_def_id(id); + let scheme = cx.lookup_item_type(def_id); + let predicates = cx.lookup_predicates(def_id); + cx.construct_parameter_environment(impl_item.span, + &scheme.generics, + &predicates, + cx.region_maps.item_extent(id)) + } + hir::ImplItemKind::Method(_, ref body) => { + let method_def_id = cx.map.local_def_id(id); + match cx.impl_or_trait_item(method_def_id) { + MethodTraitItem(ref method_ty) => { + let method_generics = &method_ty.generics; + let method_bounds = &method_ty.predicates; + cx.construct_parameter_environment( + impl_item.span, + method_generics, + method_bounds, + cx.region_maps.call_site_extent(id, body.id)) + } + _ => { + cx.sess + .bug("ParameterEnvironment::for_item(): \ + got non-method item from impl method?!") + } + } + } + } + } + Some(ast_map::NodeTraitItem(trait_item)) => { + match trait_item.node { + hir::TypeTraitItem(..) => { + // associated types don't have their own entry (for some reason), + // so for now just grab environment for the trait + let trait_id = cx.map.get_parent(id); + let trait_def_id = cx.map.local_def_id(trait_id); + let trait_def = cx.lookup_trait_def(trait_def_id); + let predicates = cx.lookup_predicates(trait_def_id); + cx.construct_parameter_environment(trait_item.span, + &trait_def.generics, + &predicates, + cx.region_maps.item_extent(id)) + } + hir::ConstTraitItem(..) => { + let def_id = cx.map.local_def_id(id); + let scheme = cx.lookup_item_type(def_id); + let predicates = cx.lookup_predicates(def_id); + cx.construct_parameter_environment(trait_item.span, + &scheme.generics, + &predicates, + cx.region_maps.item_extent(id)) + } + hir::MethodTraitItem(_, ref body) => { + // Use call-site for extent (unless this is a + // trait method with no default; then fallback + // to the method id). + let method_def_id = cx.map.local_def_id(id); + match cx.impl_or_trait_item(method_def_id) { + MethodTraitItem(ref method_ty) => { + let method_generics = &method_ty.generics; + let method_bounds = &method_ty.predicates; + let extent = if let Some(ref body) = *body { + // default impl: use call_site extent as free_id_outlive bound. + cx.region_maps.call_site_extent(id, body.id) + } else { + // no default impl: use item extent as free_id_outlive bound. + cx.region_maps.item_extent(id) + }; + cx.construct_parameter_environment( + trait_item.span, + method_generics, + method_bounds, + extent) + } + _ => { + cx.sess + .bug("ParameterEnvironment::for_item(): \ + got non-method item from provided \ + method?!") + } + } + } + } + } + Some(ast_map::NodeItem(item)) => { + match item.node { + hir::ItemFn(_, _, _, _, _, ref body) => { + // We assume this is a function. + let fn_def_id = cx.map.local_def_id(id); + let fn_scheme = cx.lookup_item_type(fn_def_id); + let fn_predicates = cx.lookup_predicates(fn_def_id); + + cx.construct_parameter_environment(item.span, + &fn_scheme.generics, + &fn_predicates, + cx.region_maps.call_site_extent(id, + body.id)) + } + hir::ItemEnum(..) | + hir::ItemStruct(..) | + hir::ItemImpl(..) | + hir::ItemConst(..) | + hir::ItemStatic(..) => { + let def_id = cx.map.local_def_id(id); + let scheme = cx.lookup_item_type(def_id); + let predicates = cx.lookup_predicates(def_id); + cx.construct_parameter_environment(item.span, + &scheme.generics, + &predicates, + cx.region_maps.item_extent(id)) + } + hir::ItemTrait(..) => { + let def_id = cx.map.local_def_id(id); + let trait_def = cx.lookup_trait_def(def_id); + let predicates = cx.lookup_predicates(def_id); + cx.construct_parameter_environment(item.span, + &trait_def.generics, + &predicates, + cx.region_maps.item_extent(id)) + } + _ => { + cx.sess.span_bug(item.span, + "ParameterEnvironment::from_item(): + can't create a parameter \ + environment for this kind of item") + } + } + } + Some(ast_map::NodeExpr(..)) => { + // This is a convenience to allow closures to work. + ParameterEnvironment::for_item(cx, cx.map.get_parent(id)) + } + _ => { + cx.sess.bug(&format!("ParameterEnvironment::from_item(): \ + `{}` is not an item", + cx.map.node_to_string(id))) + } + } + } +} + +/// A "type scheme", in ML terminology, is a type combined with some +/// set of generic types that the type is, well, generic over. In Rust +/// terms, it is the "type" of a fn item or struct -- this type will +/// include various generic parameters that must be substituted when +/// the item/struct is referenced. That is called converting the type +/// scheme to a monotype. +/// +/// - `generics`: the set of type parameters and their bounds +/// - `ty`: the base types, which may reference the parameters defined +/// in `generics` +/// +/// Note that TypeSchemes are also sometimes called "polytypes" (and +/// in fact this struct used to carry that name, so you may find some +/// stray references in a comment or something). We try to reserve the +/// "poly" prefix to refer to higher-ranked things, as in +/// `PolyTraitRef`. +/// +/// Note that each item also comes with predicates, see +/// `lookup_predicates`. +#[derive(Clone, Debug)] +pub struct TypeScheme<'tcx> { + pub generics: Generics<'tcx>, + pub ty: Ty<'tcx>, +} + +bitflags! { + flags AdtFlags: u32 { + const NO_ADT_FLAGS = 0, + const IS_ENUM = 1 << 0, + const IS_DTORCK = 1 << 1, // is this a dtorck type? + const IS_DTORCK_VALID = 1 << 2, + const IS_PHANTOM_DATA = 1 << 3, + const IS_SIMD = 1 << 4, + const IS_FUNDAMENTAL = 1 << 5, + const IS_NO_DROP_FLAG = 1 << 6, + } +} + +pub type AdtDef<'tcx> = &'tcx AdtDefData<'tcx, 'static>; +pub type VariantDef<'tcx> = &'tcx VariantDefData<'tcx, 'static>; +pub type FieldDef<'tcx> = &'tcx FieldDefData<'tcx, 'static>; + +// See comment on AdtDefData for explanation +pub type AdtDefMaster<'tcx> = &'tcx AdtDefData<'tcx, 'tcx>; +pub type VariantDefMaster<'tcx> = &'tcx VariantDefData<'tcx, 'tcx>; +pub type FieldDefMaster<'tcx> = &'tcx FieldDefData<'tcx, 'tcx>; + +pub struct VariantDefData<'tcx, 'container: 'tcx> { + /// The variant's DefId. If this is a tuple-like struct, + /// this is the DefId of the struct's ctor. + pub did: DefId, + pub name: Name, // struct's name if this is a struct + pub disr_val: Disr, + pub fields: Vec>, + pub kind: VariantKind, +} + +pub struct FieldDefData<'tcx, 'container: 'tcx> { + /// The field's DefId. NOTE: the fields of tuple-like enum variants + /// are not real items, and don't have entries in tcache etc. + pub did: DefId, + pub name: Name, + pub vis: hir::Visibility, + /// TyIVar is used here to allow for variance (see the doc at + /// AdtDefData). + /// + /// Note: direct accesses to `ty` must also add dep edges. + ty: ivar::TyIVar<'tcx, 'container> +} + +/// The definition of an abstract data type - a struct or enum. +/// +/// These are all interned (by intern_adt_def) into the adt_defs +/// table. +/// +/// Because of the possibility of nested tcx-s, this type +/// needs 2 lifetimes: the traditional variant lifetime ('tcx) +/// bounding the lifetime of the inner types is of course necessary. +/// However, it is not sufficient - types from a child tcx must +/// not be leaked into the master tcx by being stored in an AdtDefData. +/// +/// The 'container lifetime ensures that by outliving the container +/// tcx and preventing shorter-lived types from being inserted. When +/// write access is not needed, the 'container lifetime can be +/// erased to 'static, which can be done by the AdtDef wrapper. +pub struct AdtDefData<'tcx, 'container: 'tcx> { + pub did: DefId, + pub variants: Vec>, + destructor: Cell>, + flags: Cell, +} + +impl<'tcx, 'container> PartialEq for AdtDefData<'tcx, 'container> { + // AdtDefData are always interned and this is part of TyS equality + #[inline] + fn eq(&self, other: &Self) -> bool { self as *const _ == other as *const _ } +} + +impl<'tcx, 'container> Eq for AdtDefData<'tcx, 'container> {} + +impl<'tcx, 'container> Hash for AdtDefData<'tcx, 'container> { + #[inline] + fn hash(&self, s: &mut H) { + (self as *const AdtDefData).hash(s) + } +} + +impl<'tcx> Encodable for AdtDef<'tcx> { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + self.did.encode(s) + } +} + +impl<'tcx> Decodable for AdtDef<'tcx> { + fn decode(d: &mut D) -> Result, D::Error> { + let def_id: DefId = Decodable::decode(d)?; + + cstore::tls::with_decoding_context(d, |dcx, _| { + let def_id = dcx.translate_def_id(def_id); + Ok(dcx.tcx().lookup_adt_def(def_id)) + }) + } +} + + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum AdtKind { Struct, Enum } + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +pub enum VariantKind { Struct, Tuple, Unit } + +impl VariantKind { + pub fn from_variant_data(vdata: &hir::VariantData) -> Self { + match *vdata { + hir::VariantData::Struct(..) => VariantKind::Struct, + hir::VariantData::Tuple(..) => VariantKind::Tuple, + hir::VariantData::Unit(..) => VariantKind::Unit, + } + } +} + +impl<'tcx, 'container> AdtDefData<'tcx, 'container> { + fn new(tcx: &TyCtxt<'tcx>, + did: DefId, + kind: AdtKind, + variants: Vec>) -> Self { + let mut flags = AdtFlags::NO_ADT_FLAGS; + let attrs = tcx.get_attrs(did); + if attr::contains_name(&attrs, "fundamental") { + flags = flags | AdtFlags::IS_FUNDAMENTAL; + } + if attr::contains_name(&attrs, "unsafe_no_drop_flag") { + flags = flags | AdtFlags::IS_NO_DROP_FLAG; + } + if tcx.lookup_simd(did) { + flags = flags | AdtFlags::IS_SIMD; + } + if Some(did) == tcx.lang_items.phantom_data() { + flags = flags | AdtFlags::IS_PHANTOM_DATA; + } + if let AdtKind::Enum = kind { + flags = flags | AdtFlags::IS_ENUM; + } + AdtDefData { + did: did, + variants: variants, + flags: Cell::new(flags), + destructor: Cell::new(None) + } + } + + fn calculate_dtorck(&'tcx self, tcx: &TyCtxt<'tcx>) { + if tcx.is_adt_dtorck(self) { + self.flags.set(self.flags.get() | AdtFlags::IS_DTORCK); + } + self.flags.set(self.flags.get() | AdtFlags::IS_DTORCK_VALID) + } + + /// Returns the kind of the ADT - Struct or Enum. + #[inline] + pub fn adt_kind(&self) -> AdtKind { + if self.flags.get().intersects(AdtFlags::IS_ENUM) { + AdtKind::Enum + } else { + AdtKind::Struct + } + } + + /// Returns whether this is a dtorck type. If this returns + /// true, this type being safe for destruction requires it to be + /// alive; Otherwise, only the contents are required to be. + #[inline] + pub fn is_dtorck(&'tcx self, tcx: &TyCtxt<'tcx>) -> bool { + if !self.flags.get().intersects(AdtFlags::IS_DTORCK_VALID) { + self.calculate_dtorck(tcx) + } + self.flags.get().intersects(AdtFlags::IS_DTORCK) + } + + /// Returns whether this type is #[fundamental] for the purposes + /// of coherence checking. + #[inline] + pub fn is_fundamental(&self) -> bool { + self.flags.get().intersects(AdtFlags::IS_FUNDAMENTAL) + } + + #[inline] + pub fn is_simd(&self) -> bool { + self.flags.get().intersects(AdtFlags::IS_SIMD) + } + + /// Returns true if this is PhantomData. + #[inline] + pub fn is_phantom_data(&self) -> bool { + self.flags.get().intersects(AdtFlags::IS_PHANTOM_DATA) + } + + /// Returns whether this type has a destructor. + pub fn has_dtor(&self) -> bool { + match self.dtor_kind() { + NoDtor => false, + TraitDtor(..) => true + } + } + + /// Asserts this is a struct and returns the struct's unique + /// variant. + pub fn struct_variant(&self) -> &VariantDefData<'tcx, 'container> { + assert_eq!(self.adt_kind(), AdtKind::Struct); + &self.variants[0] + } + + #[inline] + pub fn type_scheme(&self, tcx: &TyCtxt<'tcx>) -> TypeScheme<'tcx> { + tcx.lookup_item_type(self.did) + } + + #[inline] + pub fn predicates(&self, tcx: &TyCtxt<'tcx>) -> GenericPredicates<'tcx> { + tcx.lookup_predicates(self.did) + } + + /// Returns an iterator over all fields contained + /// by this ADT. + #[inline] + pub fn all_fields(&self) -> + iter::FlatMap< + slice::Iter>, + slice::Iter>, + for<'s> fn(&'s VariantDefData<'tcx, 'container>) + -> slice::Iter<'s, FieldDefData<'tcx, 'container>> + > { + self.variants.iter().flat_map(VariantDefData::fields_iter) + } + + #[inline] + pub fn is_empty(&self) -> bool { + self.variants.is_empty() + } + + #[inline] + pub fn is_univariant(&self) -> bool { + self.variants.len() == 1 + } + + pub fn is_payloadfree(&self) -> bool { + !self.variants.is_empty() && + self.variants.iter().all(|v| v.fields.is_empty()) + } + + pub fn variant_with_id(&self, vid: DefId) -> &VariantDefData<'tcx, 'container> { + self.variants + .iter() + .find(|v| v.did == vid) + .expect("variant_with_id: unknown variant") + } + + pub fn variant_index_with_id(&self, vid: DefId) -> usize { + self.variants + .iter() + .position(|v| v.did == vid) + .expect("variant_index_with_id: unknown variant") + } + + pub fn variant_of_def(&self, def: Def) -> &VariantDefData<'tcx, 'container> { + match def { + Def::Variant(_, vid) => self.variant_with_id(vid), + Def::Struct(..) | Def::TyAlias(..) => self.struct_variant(), + _ => panic!("unexpected def {:?} in variant_of_def", def) + } + } + + pub fn destructor(&self) -> Option { + self.destructor.get() + } + + pub fn set_destructor(&self, dtor: DefId) { + self.destructor.set(Some(dtor)); + } + + pub fn dtor_kind(&self) -> DtorKind { + match self.destructor.get() { + Some(_) => { + TraitDtor(!self.flags.get().intersects(AdtFlags::IS_NO_DROP_FLAG)) + } + None => NoDtor, + } + } +} + +impl<'tcx, 'container> VariantDefData<'tcx, 'container> { + #[inline] + fn fields_iter(&self) -> slice::Iter> { + self.fields.iter() + } + + pub fn kind(&self) -> VariantKind { + self.kind + } + + pub fn is_tuple_struct(&self) -> bool { + self.kind() == VariantKind::Tuple + } + + #[inline] + pub fn find_field_named(&self, + name: ast::Name) + -> Option<&FieldDefData<'tcx, 'container>> { + self.fields.iter().find(|f| f.name == name) + } + + #[inline] + pub fn index_of_field_named(&self, + name: ast::Name) + -> Option { + self.fields.iter().position(|f| f.name == name) + } + + #[inline] + pub fn field_named(&self, name: ast::Name) -> &FieldDefData<'tcx, 'container> { + self.find_field_named(name).unwrap() + } +} + +impl<'tcx, 'container> FieldDefData<'tcx, 'container> { + pub fn new(did: DefId, + name: Name, + vis: hir::Visibility) -> Self { + FieldDefData { + did: did, + name: name, + vis: vis, + ty: ivar::TyIVar::new() + } + } + + pub fn ty(&self, tcx: &TyCtxt<'tcx>, subst: &Substs<'tcx>) -> Ty<'tcx> { + self.unsubst_ty().subst(tcx, subst) + } + + pub fn unsubst_ty(&self) -> Ty<'tcx> { + self.ty.unwrap(DepNode::FieldTy(self.did)) + } + + pub fn fulfill_ty(&self, ty: Ty<'container>) { + self.ty.fulfill(DepNode::FieldTy(self.did), ty); + } +} + +/// Records the substitutions used to translate the polytype for an +/// item into the monotype of an item reference. +#[derive(Clone)] +pub struct ItemSubsts<'tcx> { + pub substs: Substs<'tcx>, +} + +#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)] +pub enum ClosureKind { + // Warning: Ordering is significant here! The ordering is chosen + // because the trait Fn is a subtrait of FnMut and so in turn, and + // hence we order it so that Fn < FnMut < FnOnce. + Fn, + FnMut, + FnOnce, +} + +impl ClosureKind { + pub fn trait_did(&self, cx: &TyCtxt) -> DefId { + let result = match *self { + ClosureKind::Fn => cx.lang_items.require(FnTraitLangItem), + ClosureKind::FnMut => { + cx.lang_items.require(FnMutTraitLangItem) + } + ClosureKind::FnOnce => { + cx.lang_items.require(FnOnceTraitLangItem) + } + }; + match result { + Ok(trait_did) => trait_did, + Err(err) => cx.sess.fatal(&err[..]), + } + } + + /// True if this a type that impls this closure kind + /// must also implement `other`. + pub fn extends(self, other: ty::ClosureKind) -> bool { + match (self, other) { + (ClosureKind::Fn, ClosureKind::Fn) => true, + (ClosureKind::Fn, ClosureKind::FnMut) => true, + (ClosureKind::Fn, ClosureKind::FnOnce) => true, + (ClosureKind::FnMut, ClosureKind::FnMut) => true, + (ClosureKind::FnMut, ClosureKind::FnOnce) => true, + (ClosureKind::FnOnce, ClosureKind::FnOnce) => true, + _ => false, + } + } +} + +impl<'tcx> TyS<'tcx> { + /// Iterator that walks `self` and any types reachable from + /// `self`, in depth-first order. Note that just walks the types + /// that appear in `self`, it does not descend into the fields of + /// structs or variants. For example: + /// + /// ```notrust + /// isize => { isize } + /// Foo> => { Foo>, Bar, isize } + /// [isize] => { [isize], isize } + /// ``` + pub fn walk(&'tcx self) -> TypeWalker<'tcx> { + TypeWalker::new(self) + } + + /// Iterator that walks the immediate children of `self`. Hence + /// `Foo, u32>` yields the sequence `[Bar, u32]` + /// (but not `i32`, like `walk`). + pub fn walk_shallow(&'tcx self) -> IntoIter> { + walk::walk_shallow(self) + } + + /// Walks `ty` and any types appearing within `ty`, invoking the + /// callback `f` on each type. If the callback returns false, then the + /// children of the current type are ignored. + /// + /// Note: prefer `ty.walk()` where possible. + pub fn maybe_walk(&'tcx self, mut f: F) + where F : FnMut(Ty<'tcx>) -> bool + { + let mut walker = self.walk(); + while let Some(ty) = walker.next() { + if !f(ty) { + walker.skip_current_subtree(); + } + } + } +} + +impl<'tcx> ItemSubsts<'tcx> { + pub fn empty() -> ItemSubsts<'tcx> { + ItemSubsts { substs: Substs::empty() } + } + + pub fn is_noop(&self) -> bool { + self.substs.is_noop() + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum LvaluePreference { + PreferMutLvalue, + NoPreference +} + +impl LvaluePreference { + pub fn from_mutbl(m: hir::Mutability) -> Self { + match m { + hir::MutMutable => PreferMutLvalue, + hir::MutImmutable => NoPreference, + } + } +} + +/// Helper for looking things up in the various maps that are populated during +/// typeck::collect (e.g., `cx.impl_or_trait_items`, `cx.tcache`, etc). All of +/// these share the pattern that if the id is local, it should have been loaded +/// into the map by the `typeck::collect` phase. If the def-id is external, +/// then we have to go consult the crate loading code (and cache the result for +/// the future). +fn lookup_locally_or_in_crate_store(descr: &str, + def_id: DefId, + map: &M, + load_external: F) + -> M::Value where + M: MemoizationMap, + F: FnOnce() -> M::Value, +{ + map.memoize(def_id, || { + if def_id.is_local() { + panic!("No def'n found for {:?} in tcx.{}", def_id, descr); + } + load_external() + }) +} + +impl BorrowKind { + pub fn from_mutbl(m: hir::Mutability) -> BorrowKind { + match m { + hir::MutMutable => MutBorrow, + hir::MutImmutable => ImmBorrow, + } + } + + /// Returns a mutability `m` such that an `&m T` pointer could be used to obtain this borrow + /// kind. Because borrow kinds are richer than mutabilities, we sometimes have to pick a + /// mutability that is stronger than necessary so that it at least *would permit* the borrow in + /// question. + pub fn to_mutbl_lossy(self) -> hir::Mutability { + match self { + MutBorrow => hir::MutMutable, + ImmBorrow => hir::MutImmutable, + + // We have no type corresponding to a unique imm borrow, so + // use `&mut`. It gives all the capabilities of an `&uniq` + // and hence is a safe "over approximation". + UniqueImmBorrow => hir::MutMutable, + } + } + + pub fn to_user_str(&self) -> &'static str { + match *self { + MutBorrow => "mutable", + ImmBorrow => "immutable", + UniqueImmBorrow => "uniquely immutable", + } + } +} + +impl<'tcx> TyCtxt<'tcx> { + pub fn node_id_to_type(&self, id: NodeId) -> Ty<'tcx> { + match self.node_id_to_type_opt(id) { + Some(ty) => ty, + None => self.sess.bug( + &format!("node_id_to_type: no type for node `{}`", + self.map.node_to_string(id))) + } + } + + pub fn node_id_to_type_opt(&self, id: NodeId) -> Option> { + self.tables.borrow().node_types.get(&id).cloned() + } + + pub fn node_id_item_substs(&self, id: NodeId) -> ItemSubsts<'tcx> { + match self.tables.borrow().item_substs.get(&id) { + None => ItemSubsts::empty(), + Some(ts) => ts.clone(), + } + } + + // Returns the type of a pattern as a monotype. Like @expr_ty, this function + // doesn't provide type parameter substitutions. + pub fn pat_ty(&self, pat: &hir::Pat) -> Ty<'tcx> { + self.node_id_to_type(pat.id) + } + pub fn pat_ty_opt(&self, pat: &hir::Pat) -> Option> { + self.node_id_to_type_opt(pat.id) + } + + // Returns the type of an expression as a monotype. + // + // NB (1): This is the PRE-ADJUSTMENT TYPE for the expression. That is, in + // some cases, we insert `AutoAdjustment` annotations such as auto-deref or + // auto-ref. The type returned by this function does not consider such + // adjustments. See `expr_ty_adjusted()` instead. + // + // NB (2): This type doesn't provide type parameter substitutions; e.g. if you + // ask for the type of "id" in "id(3)", it will return "fn(&isize) -> isize" + // instead of "fn(ty) -> T with T = isize". + pub fn expr_ty(&self, expr: &hir::Expr) -> Ty<'tcx> { + self.node_id_to_type(expr.id) + } + + pub fn expr_ty_opt(&self, expr: &hir::Expr) -> Option> { + self.node_id_to_type_opt(expr.id) + } + + /// Returns the type of `expr`, considering any `AutoAdjustment` + /// entry recorded for that expression. + /// + /// It would almost certainly be better to store the adjusted ty in with + /// the `AutoAdjustment`, but I opted not to do this because it would + /// require serializing and deserializing the type and, although that's not + /// hard to do, I just hate that code so much I didn't want to touch it + /// unless it was to fix it properly, which seemed a distraction from the + /// thread at hand! -nmatsakis + pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> Ty<'tcx> { + self.expr_ty(expr) + .adjust(self, expr.span, expr.id, + self.tables.borrow().adjustments.get(&expr.id), + |method_call| { + self.tables.borrow().method_map.get(&method_call).map(|method| method.ty) + }) + } + + pub fn expr_ty_adjusted_opt(&self, expr: &hir::Expr) -> Option> { + self.expr_ty_opt(expr).map(|t| t.adjust(self, + expr.span, + expr.id, + self.tables.borrow().adjustments.get(&expr.id), + |method_call| { + self.tables.borrow().method_map.get(&method_call).map(|method| method.ty) + })) + } + + pub fn expr_span(&self, id: NodeId) -> Span { + match self.map.find(id) { + Some(ast_map::NodeExpr(e)) => { + e.span + } + Some(f) => { + self.sess.bug(&format!("Node id {} is not an expr: {:?}", + id, f)); + } + None => { + self.sess.bug(&format!("Node id {} is not present \ + in the node map", id)); + } + } + } + + pub fn local_var_name_str(&self, id: NodeId) -> InternedString { + match self.map.find(id) { + Some(ast_map::NodeLocal(pat)) => { + match pat.node { + PatKind::Ident(_, ref path1, _) => path1.node.name.as_str(), + _ => { + self.sess.bug(&format!("Variable id {} maps to {:?}, not local", id, pat)); + }, + } + }, + r => self.sess.bug(&format!("Variable id {} maps to {:?}, not local", id, r)), + } + } + + pub fn resolve_expr(&self, expr: &hir::Expr) -> Def { + match self.def_map.borrow().get(&expr.id) { + Some(def) => def.full_def(), + None => { + self.sess.span_bug(expr.span, &format!( + "no def-map entry for expr {}", expr.id)); + } + } + } + + pub fn expr_is_lval(&self, expr: &hir::Expr) -> bool { + match expr.node { + hir::ExprPath(..) => { + // We can't use resolve_expr here, as this needs to run on broken + // programs. We don't need to through - associated items are all + // rvalues. + match self.def_map.borrow().get(&expr.id) { + Some(&def::PathResolution { + base_def: Def::Static(..), .. + }) | Some(&def::PathResolution { + base_def: Def::Upvar(..), .. + }) | Some(&def::PathResolution { + base_def: Def::Local(..), .. + }) => { + true + } + Some(&def::PathResolution { base_def: Def::Err, .. })=> true, + Some(..) => false, + None => self.sess.span_bug(expr.span, &format!( + "no def for path {}", expr.id)) + } + } + + hir::ExprType(ref e, _) => { + self.expr_is_lval(e) + } + + hir::ExprUnary(hir::UnDeref, _) | + hir::ExprField(..) | + hir::ExprTupField(..) | + hir::ExprIndex(..) => { + true + } + + hir::ExprCall(..) | + hir::ExprMethodCall(..) | + hir::ExprStruct(..) | + hir::ExprTup(..) | + hir::ExprIf(..) | + hir::ExprMatch(..) | + hir::ExprClosure(..) | + hir::ExprBlock(..) | + hir::ExprRepeat(..) | + hir::ExprVec(..) | + hir::ExprBreak(..) | + hir::ExprAgain(..) | + hir::ExprRet(..) | + hir::ExprWhile(..) | + hir::ExprLoop(..) | + hir::ExprAssign(..) | + hir::ExprInlineAsm(..) | + hir::ExprAssignOp(..) | + hir::ExprLit(_) | + hir::ExprUnary(..) | + hir::ExprBox(..) | + hir::ExprAddrOf(..) | + hir::ExprBinary(..) | + hir::ExprCast(..) => { + false + } + } + } + + pub fn provided_trait_methods(&self, id: DefId) -> Vec>> { + if let Some(id) = self.map.as_local_node_id(id) { + if let ItemTrait(_, _, _, ref ms) = self.map.expect_item(id).node { + ms.iter().filter_map(|ti| { + if let hir::MethodTraitItem(_, Some(_)) = ti.node { + match self.impl_or_trait_item(self.map.local_def_id(ti.id)) { + MethodTraitItem(m) => Some(m), + _ => { + self.sess.bug("provided_trait_methods(): \ + non-method item found from \ + looking up provided method?!") + } + } + } else { + None + } + }).collect() + } else { + self.sess.bug(&format!("provided_trait_methods: `{:?}` is not a trait", id)) + } + } else { + self.sess.cstore.provided_trait_methods(self, id) + } + } + + pub fn associated_consts(&self, id: DefId) -> Vec>> { + if let Some(id) = self.map.as_local_node_id(id) { + match self.map.expect_item(id).node { + ItemTrait(_, _, _, ref tis) => { + tis.iter().filter_map(|ti| { + if let hir::ConstTraitItem(_, _) = ti.node { + match self.impl_or_trait_item(self.map.local_def_id(ti.id)) { + ConstTraitItem(ac) => Some(ac), + _ => { + self.sess.bug("associated_consts(): \ + non-const item found from \ + looking up a constant?!") + } + } + } else { + None + } + }).collect() + } + ItemImpl(_, _, _, _, _, ref iis) => { + iis.iter().filter_map(|ii| { + if let hir::ImplItemKind::Const(_, _) = ii.node { + match self.impl_or_trait_item(self.map.local_def_id(ii.id)) { + ConstTraitItem(ac) => Some(ac), + _ => { + self.sess.bug("associated_consts(): \ + non-const item found from \ + looking up a constant?!") + } + } + } else { + None + } + }).collect() + } + _ => { + self.sess.bug(&format!("associated_consts: `{:?}` is not a trait \ + or impl", id)) + } + } + } else { + self.sess.cstore.associated_consts(self, id) + } + } + + pub fn trait_impl_polarity(&self, id: DefId) -> Option { + if let Some(id) = self.map.as_local_node_id(id) { + match self.map.find(id) { + Some(ast_map::NodeItem(item)) => { + match item.node { + hir::ItemImpl(_, polarity, _, _, _, _) => Some(polarity), + _ => None + } + } + _ => None + } + } else { + self.sess.cstore.impl_polarity(id) + } + } + + pub fn custom_coerce_unsized_kind(&self, did: DefId) -> adjustment::CustomCoerceUnsized { + self.custom_coerce_unsized_kinds.memoize(did, || { + let (kind, src) = if did.krate != LOCAL_CRATE { + (self.sess.cstore.custom_coerce_unsized_kind(did), "external") + } else { + (None, "local") + }; + + match kind { + Some(kind) => kind, + None => { + self.sess.bug(&format!("custom_coerce_unsized_kind: \ + {} impl `{}` is missing its kind", + src, self.item_path_str(did))); + } + } + }) + } + + pub fn impl_or_trait_item(&self, id: DefId) -> ImplOrTraitItem<'tcx> { + lookup_locally_or_in_crate_store( + "impl_or_trait_items", id, &self.impl_or_trait_items, + || self.sess.cstore.impl_or_trait_item(self, id) + .expect("missing ImplOrTraitItem in metadata")) + } + + pub fn trait_item_def_ids(&self, id: DefId) -> Rc> { + lookup_locally_or_in_crate_store( + "trait_item_def_ids", id, &self.trait_item_def_ids, + || Rc::new(self.sess.cstore.trait_item_def_ids(id))) + } + + /// Returns the trait-ref corresponding to a given impl, or None if it is + /// an inherent impl. + pub fn impl_trait_ref(&self, id: DefId) -> Option> { + lookup_locally_or_in_crate_store( + "impl_trait_refs", id, &self.impl_trait_refs, + || self.sess.cstore.impl_trait_ref(self, id)) + } + + /// Returns whether this DefId refers to an impl + pub fn is_impl(&self, id: DefId) -> bool { + if let Some(id) = self.map.as_local_node_id(id) { + if let Some(ast_map::NodeItem( + &hir::Item { node: hir::ItemImpl(..), .. })) = self.map.find(id) { + true + } else { + false + } + } else { + self.sess.cstore.is_impl(id) + } + } + + pub fn trait_ref_to_def_id(&self, tr: &hir::TraitRef) -> DefId { + self.def_map.borrow().get(&tr.ref_id).expect("no def-map entry for trait").def_id() + } + + pub fn def_key(&self, id: DefId) -> ast_map::DefKey { + if id.is_local() { + self.map.def_key(id) + } else { + self.sess.cstore.def_key(id) + } + } + + /// Returns the `DefPath` of an item. Note that if `id` is not + /// local to this crate -- or is inlined into this crate -- the + /// result will be a non-local `DefPath`. + pub fn def_path(&self, id: DefId) -> ast_map::DefPath { + if id.is_local() { + self.map.def_path(id) + } else { + self.sess.cstore.relative_def_path(id) + } + } + + pub fn with_path(&self, id: DefId, f: F) -> T where + F: FnOnce(ast_map::PathElems) -> T, + { + if let Some(id) = self.map.as_local_node_id(id) { + self.map.with_path(id, f) + } else { + let mut path: Vec<_>; + if let Some(extern_crate) = self.sess.cstore.extern_crate(id.krate) { + if !extern_crate.direct { + // this comes from some crate that we don't have a direct + // path to; we'll settle for just prepending the name of + // the crate. + path = self.sess.cstore.extern_item_path(id) + } else { + // start with the path to the extern crate, then + // add the relative path to the actual item + fn collector(elems: ast_map::PathElems) -> Vec { + elems.collect() + } + path = self.with_path(extern_crate.def_id, collector); + path.extend(self.sess.cstore.relative_item_path(id)); + } + } else { + // if this was injected, just make a path with name of crate + path = self.sess.cstore.extern_item_path(id); + } + f(path.iter().cloned().chain(LinkedPath::empty())) + } + } + + pub fn item_name(&self, id: DefId) -> ast::Name { + if let Some(id) = self.map.as_local_node_id(id) { + self.map.get_path_elem(id).name() + } else { + self.sess.cstore.item_name(id) + } + } + + // Register a given item type + pub fn register_item_type(&self, did: DefId, ty: TypeScheme<'tcx>) { + self.tcache.borrow_mut().insert(did, ty); + } + + // If the given item is in an external crate, looks up its type and adds it to + // the type cache. Returns the type parameters and type. + pub fn lookup_item_type(&self, did: DefId) -> TypeScheme<'tcx> { + lookup_locally_or_in_crate_store( + "tcache", did, &self.tcache, + || self.sess.cstore.item_type(self, did)) + } + + /// Given the did of a trait, returns its canonical trait ref. + pub fn lookup_trait_def(&self, did: DefId) -> &'tcx TraitDef<'tcx> { + lookup_locally_or_in_crate_store( + "trait_defs", did, &self.trait_defs, + || self.alloc_trait_def(self.sess.cstore.trait_def(self, did)) + ) + } + + /// Given the did of an ADT, return a master reference to its + /// definition. Unless you are planning on fulfilling the ADT's fields, + /// use lookup_adt_def instead. + pub fn lookup_adt_def_master(&self, did: DefId) -> AdtDefMaster<'tcx> { + lookup_locally_or_in_crate_store( + "adt_defs", did, &self.adt_defs, + || self.sess.cstore.adt_def(self, did) + ) + } + + /// Given the did of an ADT, return a reference to its definition. + pub fn lookup_adt_def(&self, did: DefId) -> AdtDef<'tcx> { + // when reverse-variance goes away, a transmute:: + // would be needed here. + self.lookup_adt_def_master(did) + } + + /// Given the did of an item, returns its full set of predicates. + pub fn lookup_predicates(&self, did: DefId) -> GenericPredicates<'tcx> { + lookup_locally_or_in_crate_store( + "predicates", did, &self.predicates, + || self.sess.cstore.item_predicates(self, did)) + } + + /// Given the did of a trait, returns its superpredicates. + pub fn lookup_super_predicates(&self, did: DefId) -> GenericPredicates<'tcx> { + lookup_locally_or_in_crate_store( + "super_predicates", did, &self.super_predicates, + || self.sess.cstore.item_super_predicates(self, did)) + } + + /// If `type_needs_drop` returns true, then `ty` is definitely + /// non-copy and *might* have a destructor attached; if it returns + /// false, then `ty` definitely has no destructor (i.e. no drop glue). + /// + /// (Note that this implies that if `ty` has a destructor attached, + /// then `type_needs_drop` will definitely return `true` for `ty`.) + pub fn type_needs_drop_given_env<'a>(&self, + ty: Ty<'tcx>, + param_env: &ty::ParameterEnvironment<'a,'tcx>) -> bool { + // Issue #22536: We first query type_moves_by_default. It sees a + // normalized version of the type, and therefore will definitely + // know whether the type implements Copy (and thus needs no + // cleanup/drop/zeroing) ... + let implements_copy = !ty.moves_by_default(param_env, DUMMY_SP); + + if implements_copy { return false; } + + // ... (issue #22536 continued) but as an optimization, still use + // prior logic of asking if the `needs_drop` bit is set; we need + // not zero non-Copy types if they have no destructor. + + // FIXME(#22815): Note that calling `ty::type_contents` is a + // conservative heuristic; it may report that `needs_drop` is set + // when actual type does not actually have a destructor associated + // with it. But since `ty` absolutely did not have the `Copy` + // bound attached (see above), it is sound to treat it as having a + // destructor (e.g. zero its memory on move). + + let contents = ty.type_contents(self); + debug!("type_needs_drop ty={:?} contents={:?}", ty, contents); + contents.needs_drop(self) + } + + /// Get the attributes of a definition. + pub fn get_attrs(&self, did: DefId) -> Cow<'tcx, [ast::Attribute]> { + if let Some(id) = self.map.as_local_node_id(did) { + Cow::Borrowed(self.map.attrs(id)) + } else { + Cow::Owned(self.sess.cstore.item_attrs(did)) + } + } + + /// Determine whether an item is annotated with an attribute + pub fn has_attr(&self, did: DefId, attr: &str) -> bool { + self.get_attrs(did).iter().any(|item| item.check_name(attr)) + } + + /// Determine whether an item is annotated with `#[repr(packed)]` + pub fn lookup_packed(&self, did: DefId) -> bool { + self.lookup_repr_hints(did).contains(&attr::ReprPacked) + } + + /// Determine whether an item is annotated with `#[simd]` + pub fn lookup_simd(&self, did: DefId) -> bool { + self.has_attr(did, "simd") + || self.lookup_repr_hints(did).contains(&attr::ReprSimd) + } + + pub fn item_variances(&self, item_id: DefId) -> Rc { + lookup_locally_or_in_crate_store( + "item_variance_map", item_id, &self.item_variance_map, + || Rc::new(self.sess.cstore.item_variances(item_id))) + } + + pub fn trait_has_default_impl(&self, trait_def_id: DefId) -> bool { + self.populate_implementations_for_trait_if_necessary(trait_def_id); + + let def = self.lookup_trait_def(trait_def_id); + def.flags.get().intersects(TraitFlags::HAS_DEFAULT_IMPL) + } + + /// Records a trait-to-implementation mapping. + pub fn record_trait_has_default_impl(&self, trait_def_id: DefId) { + let def = self.lookup_trait_def(trait_def_id); + def.flags.set(def.flags.get() | TraitFlags::HAS_DEFAULT_IMPL) + } + + /// Load primitive inherent implementations if necessary + pub fn populate_implementations_for_primitive_if_necessary(&self, + primitive_def_id: DefId) { + if primitive_def_id.is_local() { + return + } + + // The primitive is not local, hence we are reading this out + // of metadata. + let _ignore = self.dep_graph.in_ignore(); + + if self.populated_external_primitive_impls.borrow().contains(&primitive_def_id) { + return + } + + debug!("populate_implementations_for_primitive_if_necessary: searching for {:?}", + primitive_def_id); + + let impl_items = self.sess.cstore.impl_items(primitive_def_id); + + // Store the implementation info. + self.impl_items.borrow_mut().insert(primitive_def_id, impl_items); + self.populated_external_primitive_impls.borrow_mut().insert(primitive_def_id); + } + + /// Populates the type context with all the inherent implementations for + /// the given type if necessary. + pub fn populate_inherent_implementations_for_type_if_necessary(&self, + type_id: DefId) { + if type_id.is_local() { + return + } + + // The type is not local, hence we are reading this out of + // metadata and don't need to track edges. + let _ignore = self.dep_graph.in_ignore(); + + if self.populated_external_types.borrow().contains(&type_id) { + return + } + + debug!("populate_inherent_implementations_for_type_if_necessary: searching for {:?}", + type_id); + + let inherent_impls = self.sess.cstore.inherent_implementations_for_type(type_id); + for &impl_def_id in &inherent_impls { + // Store the implementation info. + let impl_items = self.sess.cstore.impl_items(impl_def_id); + self.impl_items.borrow_mut().insert(impl_def_id, impl_items); + } + + self.inherent_impls.borrow_mut().insert(type_id, Rc::new(inherent_impls)); + self.populated_external_types.borrow_mut().insert(type_id); + } + + /// Populates the type context with all the implementations for the given + /// trait if necessary. + pub fn populate_implementations_for_trait_if_necessary(&self, trait_id: DefId) { + if trait_id.is_local() { + return + } + + // The type is not local, hence we are reading this out of + // metadata and don't need to track edges. + let _ignore = self.dep_graph.in_ignore(); + + let def = self.lookup_trait_def(trait_id); + if def.flags.get().intersects(TraitFlags::IMPLS_VALID) { + return; + } + + debug!("populate_implementations_for_trait_if_necessary: searching for {:?}", def); + + if self.sess.cstore.is_defaulted_trait(trait_id) { + self.record_trait_has_default_impl(trait_id); + } + + for impl_def_id in self.sess.cstore.implementations_of_trait(trait_id) { + let impl_items = self.sess.cstore.impl_items(impl_def_id); + let trait_ref = self.impl_trait_ref(impl_def_id).unwrap(); + + // Record the trait->implementation mapping. + if let Some(parent) = self.sess.cstore.impl_parent(impl_def_id) { + def.record_remote_impl(self, impl_def_id, trait_ref, parent); + } else { + def.record_remote_impl(self, impl_def_id, trait_ref, trait_id); + } + + // For any methods that use a default implementation, add them to + // the map. This is a bit unfortunate. + for impl_item_def_id in &impl_items { + let method_def_id = impl_item_def_id.def_id(); + // load impl items eagerly for convenience + // FIXME: we may want to load these lazily + self.impl_or_trait_item(method_def_id); + } + + // Store the implementation info. + self.impl_items.borrow_mut().insert(impl_def_id, impl_items); + } + + def.flags.set(def.flags.get() | TraitFlags::IMPLS_VALID); + } + + pub fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind { + Tables::closure_kind(&self.tables, self, def_id) + } + + pub fn closure_type(&self, + def_id: DefId, + substs: &ClosureSubsts<'tcx>) + -> ty::ClosureTy<'tcx> + { + Tables::closure_type(&self.tables, self, def_id, substs) + } + + /// Given the def_id of an impl, return the def_id of the trait it implements. + /// If it implements no trait, return `None`. + pub fn trait_id_of_impl(&self, def_id: DefId) -> Option { + self.impl_trait_ref(def_id).map(|tr| tr.def_id) + } + + /// If the given def ID describes a method belonging to an impl, return the + /// ID of the impl that the method belongs to. Otherwise, return `None`. + pub fn impl_of_method(&self, def_id: DefId) -> Option { + if def_id.krate != LOCAL_CRATE { + return self.sess.cstore.impl_or_trait_item(self, def_id).and_then(|item| { + match item.container() { + TraitContainer(_) => None, + ImplContainer(def_id) => Some(def_id), + } + }); + } + match self.impl_or_trait_items.borrow().get(&def_id).cloned() { + Some(trait_item) => { + match trait_item.container() { + TraitContainer(_) => None, + ImplContainer(def_id) => Some(def_id), + } + } + None => None + } + } + + /// If the given def ID describes an item belonging to a trait (either a + /// default method or an implementation of a trait method), return the ID of + /// the trait that the method belongs to. Otherwise, return `None`. + pub fn trait_of_item(&self, def_id: DefId) -> Option { + if def_id.krate != LOCAL_CRATE { + return self.sess.cstore.trait_of_item(self, def_id); + } + match self.impl_or_trait_items.borrow().get(&def_id).cloned() { + Some(impl_or_trait_item) => { + match impl_or_trait_item.container() { + TraitContainer(def_id) => Some(def_id), + ImplContainer(def_id) => self.trait_id_of_impl(def_id), + } + } + None => None + } + } + + /// If the given def ID describes an item belonging to a trait, (either a + /// default method or an implementation of a trait method), return the ID of + /// the method inside trait definition (this means that if the given def ID + /// is already that of the original trait method, then the return value is + /// the same). + /// Otherwise, return `None`. + pub fn trait_item_of_item(&self, def_id: DefId) -> Option { + let impl_item = match self.impl_or_trait_items.borrow().get(&def_id) { + Some(m) => m.clone(), + None => return None, + }; + let name = impl_item.name(); + match self.trait_of_item(def_id) { + Some(trait_did) => { + self.trait_items(trait_did).iter() + .find(|item| item.name() == name) + .map(|item| item.id()) + } + None => None + } + } + + /// Construct a parameter environment suitable for static contexts or other contexts where there + /// are no free type/lifetime parameters in scope. + pub fn empty_parameter_environment<'a>(&'a self) + -> ParameterEnvironment<'a,'tcx> { + + // for an empty parameter environment, there ARE no free + // regions, so it shouldn't matter what we use for the free id + let free_id_outlive = self.region_maps.node_extent(ast::DUMMY_NODE_ID); + ty::ParameterEnvironment { tcx: self, + free_substs: Substs::empty(), + caller_bounds: Vec::new(), + implicit_region_bound: ty::ReEmpty, + selection_cache: traits::SelectionCache::new(), + evaluation_cache: traits::EvaluationCache::new(), + free_id_outlive: free_id_outlive } + } + + /// Constructs and returns a substitution that can be applied to move from + /// the "outer" view of a type or method to the "inner" view. + /// In general, this means converting from bound parameters to + /// free parameters. Since we currently represent bound/free type + /// parameters in the same way, this only has an effect on regions. + pub fn construct_free_substs(&self, generics: &Generics<'tcx>, + free_id_outlive: CodeExtent) -> Substs<'tcx> { + // map T => T + let mut types = VecPerParamSpace::empty(); + for def in generics.types.as_slice() { + debug!("construct_parameter_environment(): push_types_from_defs: def={:?}", + def); + types.push(def.space, self.mk_param_from_def(def)); + } + + // map bound 'a => free 'a + let mut regions = VecPerParamSpace::empty(); + for def in generics.regions.as_slice() { + let region = + ReFree(FreeRegion { scope: free_id_outlive, + bound_region: BrNamed(def.def_id, def.name) }); + debug!("push_region_params {:?}", region); + regions.push(def.space, region); + } + + Substs { + types: types, + regions: regions, + } + } + + /// See `ParameterEnvironment` struct def'n for details. + /// If you were using `free_id: NodeId`, you might try `self.region_maps.item_extent(free_id)` + /// for the `free_id_outlive` parameter. (But note that that is not always quite right.) + pub fn construct_parameter_environment<'a>(&'a self, + span: Span, + generics: &ty::Generics<'tcx>, + generic_predicates: &ty::GenericPredicates<'tcx>, + free_id_outlive: CodeExtent) + -> ParameterEnvironment<'a, 'tcx> + { + // + // Construct the free substs. + // + + let free_substs = self.construct_free_substs(generics, free_id_outlive); + + // + // Compute the bounds on Self and the type parameters. + // + + let bounds = generic_predicates.instantiate(self, &free_substs); + let bounds = self.liberate_late_bound_regions(free_id_outlive, &ty::Binder(bounds)); + let predicates = bounds.predicates.into_vec(); + + // Finally, we have to normalize the bounds in the environment, in + // case they contain any associated type projections. This process + // can yield errors if the put in illegal associated types, like + // `::Bar` where `i32` does not implement `Foo`. We + // report these errors right here; this doesn't actually feel + // right to me, because constructing the environment feels like a + // kind of a "idempotent" action, but I'm not sure where would be + // a better place. In practice, we construct environments for + // every fn once during type checking, and we'll abort if there + // are any errors at that point, so after type checking you can be + // sure that this will succeed without errors anyway. + // + + let unnormalized_env = ty::ParameterEnvironment { + tcx: self, + free_substs: free_substs, + implicit_region_bound: ty::ReScope(free_id_outlive), + caller_bounds: predicates, + selection_cache: traits::SelectionCache::new(), + evaluation_cache: traits::EvaluationCache::new(), + free_id_outlive: free_id_outlive, + }; + + let cause = traits::ObligationCause::misc(span, free_id_outlive.node_id(&self.region_maps)); + traits::normalize_param_env_or_error(unnormalized_env, cause) + } + + pub fn is_method_call(&self, expr_id: NodeId) -> bool { + self.tables.borrow().method_map.contains_key(&MethodCall::expr(expr_id)) + } + + pub fn is_overloaded_autoderef(&self, expr_id: NodeId, autoderefs: u32) -> bool { + self.tables.borrow().method_map.contains_key(&MethodCall::autoderef(expr_id, + autoderefs)) + } + + pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option { + Some(self.tables.borrow().upvar_capture_map.get(&upvar_id).unwrap().clone()) + } + + pub fn visit_all_items_in_krate(&self, + dep_node_fn: F, + visitor: &mut V) + where F: FnMut(DefId) -> DepNode, V: Visitor<'tcx> + { + dep_graph::visit_all_items_in_krate(self, dep_node_fn, visitor); + } + + /// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err` + /// with the name of the crate containing the impl. + pub fn span_of_impl(&self, impl_did: DefId) -> Result { + if impl_did.is_local() { + let node_id = self.map.as_local_node_id(impl_did).unwrap(); + Ok(self.map.span(node_id)) + } else { + Err(self.sess.cstore.crate_name(impl_did.krate)) + } + } +} + +/// The category of explicit self. +#[derive(Clone, Copy, Eq, PartialEq, Debug)] +pub enum ExplicitSelfCategory { + Static, + ByValue, + ByReference(Region, hir::Mutability), + ByBox, +} + +/// A free variable referred to in a function. +#[derive(Copy, Clone, RustcEncodable, RustcDecodable)] +pub struct Freevar { + /// The variable being accessed free. + pub def: Def, + + // First span where it is accessed (there can be multiple). + pub span: Span +} + +pub type FreevarMap = NodeMap>; + +pub type CaptureModeMap = NodeMap; + +// Trait method resolution +pub type TraitMap = NodeMap>; + +// Map from the NodeId of a glob import to a list of items which are actually +// imported. +pub type GlobMap = HashMap>; + +impl<'tcx> TyCtxt<'tcx> { + pub fn with_freevars(&self, fid: NodeId, f: F) -> T where + F: FnOnce(&[Freevar]) -> T, + { + match self.freevars.borrow().get(&fid) { + None => f(&[]), + Some(d) => f(&d[..]) + } + } +} diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs new file mode 100644 index 00000000000..898c9d65c78 --- /dev/null +++ b/src/librustc/ty/outlives.rs @@ -0,0 +1,220 @@ +// Copyright 2012 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// The outlines relation `T: 'a` or `'a: 'b`. This code frequently +// refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that +// RFC for reference. + +use infer::InferCtxt; +use ty::{self, Ty, TypeFoldable}; + +#[derive(Debug)] +pub enum Component<'tcx> { + Region(ty::Region), + Param(ty::ParamTy), + UnresolvedInferenceVariable(ty::InferTy), + + // Projections like `T::Foo` are tricky because a constraint like + // `T::Foo: 'a` can be satisfied in so many ways. There may be a + // where-clause that says `T::Foo: 'a`, or the defining trait may + // include a bound like `type Foo: 'static`, or -- in the most + // conservative way -- we can prove that `T: 'a` (more generally, + // that all components in the projection outlive `'a`). This code + // is not in a position to judge which is the best technique, so + // we just product the projection as a component and leave it to + // the consumer to decide (but see `EscapingProjection` below). + Projection(ty::ProjectionTy<'tcx>), + + // In the case where a projection has escaping regions -- meaning + // regions bound within the type itself -- we always use + // the most conservative rule, which requires that all components + // outlive the bound. So for example if we had a type like this: + // + // for<'a> Trait1< >::Foo > + // ~~~~~~~~~~~~~~~~~~~~~~~~~ + // + // then the inner projection (underlined) has an escaping region + // `'a`. We consider that outer trait `'c` to meet a bound if `'b` + // outlives `'b: 'c`, and we don't consider whether the trait + // declares that `Foo: 'static` etc. Therefore, we just return the + // free components of such a projection (in this case, `'b`). + // + // However, in the future, we may want to get smarter, and + // actually return a "higher-ranked projection" here. Therefore, + // we mark that these components are part of an escaping + // projection, so that implied bounds code can avoid relying on + // them. This gives us room to improve the regionck reasoning in + // the future without breaking backwards compat. + EscapingProjection(Vec>), +} + +/// Returns all the things that must outlive `'a` for the condition +/// `ty0: 'a` to hold. +pub fn components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, + ty0: Ty<'tcx>) + -> Vec> { + let mut components = vec![]; + compute_components(infcx, ty0, &mut components); + debug!("components({:?}) = {:?}", ty0, components); + components +} + +fn compute_components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, + ty: Ty<'tcx>, + out: &mut Vec>) { + // Descend through the types, looking for the various "base" + // components and collecting them into `out`. This is not written + // with `collect()` because of the need to sometimes skip subtrees + // in the `subtys` iterator (e.g., when encountering a + // projection). + match ty.sty { + ty::TyClosure(_, ref substs) => { + // FIXME(#27086). We do not accumulate from substs, since they + // don't represent reachable data. This means that, in + // practice, some of the lifetime parameters might not + // be in scope when the body runs, so long as there is + // no reachable data with that lifetime. For better or + // worse, this is consistent with fn types, however, + // which can also encapsulate data in this fashion + // (though it's somewhat harder, and typically + // requires virtual dispatch). + // + // Note that changing this (in a naive way, at least) + // causes regressions for what appears to be perfectly + // reasonable code like this: + // + // ``` + // fn foo<'a>(p: &Data<'a>) { + // bar(|q: &mut Parser| q.read_addr()) + // } + // fn bar(p: Box) { + // } + // ``` + // + // Note that `p` (and `'a`) are not used in the + // closure at all, but to meet the requirement that + // the closure type `C: 'static` (so it can be coerced + // to the object type), we get the requirement that + // `'a: 'static` since `'a` appears in the closure + // type `C`. + // + // A smarter fix might "prune" unused `func_substs` -- + // this would avoid breaking simple examples like + // this, but would still break others (which might + // indeed be invalid, depending on your POV). Pruning + // would be a subtle process, since we have to see + // what func/type parameters are used and unused, + // taking into consideration UFCS and so forth. + + for &upvar_ty in &substs.upvar_tys { + compute_components(infcx, upvar_ty, out); + } + } + + // OutlivesTypeParameterEnv -- the actual checking that `X:'a` + // is implied by the environment is done in regionck. + ty::TyParam(p) => { + out.push(Component::Param(p)); + } + + // For projections, we prefer to generate an obligation like + // `>::Foo: 'a`, because this gives the + // regionck more ways to prove that it holds. However, + // regionck is not (at least currently) prepared to deal with + // higher-ranked regions that may appear in the + // trait-ref. Therefore, if we see any higher-ranke regions, + // we simply fallback to the most restrictive rule, which + // requires that `Pi: 'a` for all `i`. + ty::TyProjection(ref data) => { + if !data.has_escaping_regions() { + // best case: no escaping regions, so push the + // projection and skip the subtree (thus generating no + // constraints for Pi). This defers the choice between + // the rules OutlivesProjectionEnv, + // OutlivesProjectionTraitDef, and + // OutlivesProjectionComponents to regionck. + out.push(Component::Projection(*data)); + } else { + // fallback case: hard code + // OutlivesProjectionComponents. Continue walking + // through and constrain Pi. + let subcomponents = capture_components(infcx, ty); + out.push(Component::EscapingProjection(subcomponents)); + } + } + + // If we encounter an inference variable, try to resolve it + // and proceed with resolved version. If we cannot resolve it, + // then record the unresolved variable as a component. + ty::TyInfer(_) => { + let ty = infcx.resolve_type_vars_if_possible(&ty); + if let ty::TyInfer(infer_ty) = ty.sty { + out.push(Component::UnresolvedInferenceVariable(infer_ty)); + } else { + compute_components(infcx, ty, out); + } + } + + // Most types do not introduce any region binders, nor + // involve any other subtle cases, and so the WF relation + // simply constraints any regions referenced directly by + // the type and then visits the types that are lexically + // contained within. (The comments refer to relevant rules + // from RFC1214.) + ty::TyBool | // OutlivesScalar + ty::TyChar | // OutlivesScalar + ty::TyInt(..) | // OutlivesScalar + ty::TyUint(..) | // OutlivesScalar + ty::TyFloat(..) | // OutlivesScalar + ty::TyEnum(..) | // OutlivesNominalType + ty::TyStruct(..) | // OutlivesNominalType + ty::TyBox(..) | // OutlivesNominalType (ish) + ty::TyStr | // OutlivesScalar (ish) + ty::TyArray(..) | // ... + ty::TySlice(..) | // ... + ty::TyRawPtr(..) | // ... + ty::TyRef(..) | // OutlivesReference + ty::TyTuple(..) | // ... + ty::TyFnDef(..) | // OutlivesFunction (*) + ty::TyFnPtr(_) | // OutlivesFunction (*) + ty::TyTrait(..) | // OutlivesObject, OutlivesFragment (*) + ty::TyError => { + // (*) Bare functions and traits are both binders. In the + // RFC, this means we would add the bound regions to the + // "bound regions list". In our representation, no such + // list is maintained explicitly, because bound regions + // themselves can be readily identified. + + push_region_constraints(out, ty.regions()); + for subty in ty.walk_shallow() { + compute_components(infcx, subty, out); + } + } + } +} + +fn capture_components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, + ty: Ty<'tcx>) + -> Vec> { + let mut temp = vec![]; + push_region_constraints(&mut temp, ty.regions()); + for subty in ty.walk_shallow() { + compute_components(infcx, subty, &mut temp); + } + temp +} + +fn push_region_constraints<'tcx>(out: &mut Vec>, regions: Vec) { + for r in regions { + if !r.is_bound() { + out.push(Component::Region(r)); + } + } +} diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs new file mode 100644 index 00000000000..bb4f13b13c1 --- /dev/null +++ b/src/librustc/ty/relate.rs @@ -0,0 +1,684 @@ +// Copyright 2012-2013 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Generalized type relating mechanism. A type relation R relates a +//! pair of values (A, B). A and B are usually types or regions but +//! can be other things. Examples of type relations are subtyping, +//! type equality, etc. + +use middle::def_id::DefId; +use ty::subst::{ParamSpace, Substs}; +use ty::{self, Ty, TyCtxt, TypeFoldable}; +use ty::error::{ExpectedFound, TypeError}; +use std::rc::Rc; +use syntax::abi; +use rustc_front::hir as ast; + +pub type RelateResult<'tcx, T> = Result>; + +#[derive(Clone, Debug)] +pub enum Cause { + ExistentialRegionBound, // relating an existential region bound +} + +pub trait TypeRelation<'a,'tcx> : Sized { + fn tcx(&self) -> &'a TyCtxt<'tcx>; + + /// Returns a static string we can use for printouts. + fn tag(&self) -> &'static str; + + /// Returns true if the value `a` is the "expected" type in the + /// relation. Just affects error messages. + fn a_is_expected(&self) -> bool; + + fn with_cause(&mut self, _cause: Cause, f: F) -> R + where F: FnOnce(&mut Self) -> R + { + f(self) + } + + /// Generic relation routine suitable for most anything. + fn relate>(&mut self, a: &T, b: &T) -> RelateResult<'tcx, T> { + Relate::relate(self, a, b) + } + + /// Relete elements of two slices pairwise. + fn relate_zip>(&mut self, a: &[T], b: &[T]) -> RelateResult<'tcx, Vec> { + assert_eq!(a.len(), b.len()); + a.iter().zip(b).map(|(a, b)| self.relate(a, b)).collect() + } + + /// Switch variance for the purpose of relating `a` and `b`. + fn relate_with_variance>(&mut self, + variance: ty::Variance, + a: &T, + b: &T) + -> RelateResult<'tcx, T>; + + // Overrideable relations. You shouldn't typically call these + // directly, instead call `relate()`, which in turn calls + // these. This is both more uniform but also allows us to add + // additional hooks for other types in the future if needed + // without making older code, which called `relate`, obsolete. + + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) + -> RelateResult<'tcx, Ty<'tcx>>; + + fn regions(&mut self, a: ty::Region, b: ty::Region) + -> RelateResult<'tcx, ty::Region>; + + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where T: Relate<'a,'tcx>; +} + +pub trait Relate<'a,'tcx>: TypeFoldable<'tcx> { + fn relate>(relation: &mut R, + a: &Self, + b: &Self) + -> RelateResult<'tcx, Self>; +} + +/////////////////////////////////////////////////////////////////////////// +// Relate impls + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::TypeAndMut<'tcx> { + fn relate(relation: &mut R, + a: &ty::TypeAndMut<'tcx>, + b: &ty::TypeAndMut<'tcx>) + -> RelateResult<'tcx, ty::TypeAndMut<'tcx>> + where R: TypeRelation<'a,'tcx> + { + debug!("{}.mts({:?}, {:?})", + relation.tag(), + a, + b); + if a.mutbl != b.mutbl { + Err(TypeError::Mutability) + } else { + let mutbl = a.mutbl; + let variance = match mutbl { + ast::Mutability::MutImmutable => ty::Covariant, + ast::Mutability::MutMutable => ty::Invariant, + }; + let ty = relation.relate_with_variance(variance, &a.ty, &b.ty)?; + Ok(ty::TypeAndMut {ty: ty, mutbl: mutbl}) + } + } +} + +// substitutions are not themselves relatable without more context, +// but they is an important subroutine for things that ARE relatable, +// like traits etc. +fn relate_item_substs<'a,'tcx:'a,R>(relation: &mut R, + item_def_id: DefId, + a_subst: &Substs<'tcx>, + b_subst: &Substs<'tcx>) + -> RelateResult<'tcx, Substs<'tcx>> + where R: TypeRelation<'a,'tcx> +{ + debug!("substs: item_def_id={:?} a_subst={:?} b_subst={:?}", + item_def_id, + a_subst, + b_subst); + + let variances; + let opt_variances = if relation.tcx().variance_computed.get() { + variances = relation.tcx().item_variances(item_def_id); + Some(&*variances) + } else { + None + }; + relate_substs(relation, opt_variances, a_subst, b_subst) +} + +pub fn relate_substs<'a,'tcx:'a,R>(relation: &mut R, + variances: Option<&ty::ItemVariances>, + a_subst: &Substs<'tcx>, + b_subst: &Substs<'tcx>) + -> RelateResult<'tcx, Substs<'tcx>> + where R: TypeRelation<'a,'tcx> +{ + let mut substs = Substs::empty(); + + for &space in &ParamSpace::all() { + let a_tps = a_subst.types.get_slice(space); + let b_tps = b_subst.types.get_slice(space); + let t_variances = variances.map(|v| v.types.get_slice(space)); + let tps = relate_type_params(relation, t_variances, a_tps, b_tps)?; + substs.types.replace(space, tps); + } + + for &space in &ParamSpace::all() { + let a_regions = a_subst.regions.get_slice(space); + let b_regions = b_subst.regions.get_slice(space); + let r_variances = variances.map(|v| v.regions.get_slice(space)); + let regions = relate_region_params(relation, + r_variances, + a_regions, + b_regions)?; + substs.regions.replace(space, regions); + } + + Ok(substs) +} + +fn relate_type_params<'a,'tcx:'a,R>(relation: &mut R, + variances: Option<&[ty::Variance]>, + a_tys: &[Ty<'tcx>], + b_tys: &[Ty<'tcx>]) + -> RelateResult<'tcx, Vec>> + where R: TypeRelation<'a,'tcx> +{ + if a_tys.len() != b_tys.len() { + return Err(TypeError::TyParamSize(expected_found(relation, + &a_tys.len(), + &b_tys.len()))); + } + + (0 .. a_tys.len()) + .map(|i| { + let a_ty = a_tys[i]; + let b_ty = b_tys[i]; + let v = variances.map_or(ty::Invariant, |v| v[i]); + relation.relate_with_variance(v, &a_ty, &b_ty) + }) + .collect() +} + +fn relate_region_params<'a,'tcx:'a,R>(relation: &mut R, + variances: Option<&[ty::Variance]>, + a_rs: &[ty::Region], + b_rs: &[ty::Region]) + -> RelateResult<'tcx, Vec> + where R: TypeRelation<'a,'tcx> +{ + let num_region_params = a_rs.len(); + + debug!("relate_region_params(a_rs={:?}, \ + b_rs={:?}, variances={:?})", + a_rs, + b_rs, + variances); + + assert_eq!(num_region_params, + variances.map_or(num_region_params, + |v| v.len())); + + assert_eq!(num_region_params, b_rs.len()); + + (0..a_rs.len()) + .map(|i| { + let a_r = a_rs[i]; + let b_r = b_rs[i]; + let variance = variances.map_or(ty::Invariant, |v| v[i]); + relation.relate_with_variance(variance, &a_r, &b_r) + }) + .collect() +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::BareFnTy<'tcx> { + fn relate(relation: &mut R, + a: &ty::BareFnTy<'tcx>, + b: &ty::BareFnTy<'tcx>) + -> RelateResult<'tcx, ty::BareFnTy<'tcx>> + where R: TypeRelation<'a,'tcx> + { + let unsafety = relation.relate(&a.unsafety, &b.unsafety)?; + let abi = relation.relate(&a.abi, &b.abi)?; + let sig = relation.relate(&a.sig, &b.sig)?; + Ok(ty::BareFnTy {unsafety: unsafety, + abi: abi, + sig: sig}) + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::FnSig<'tcx> { + fn relate(relation: &mut R, + a: &ty::FnSig<'tcx>, + b: &ty::FnSig<'tcx>) + -> RelateResult<'tcx, ty::FnSig<'tcx>> + where R: TypeRelation<'a,'tcx> + { + if a.variadic != b.variadic { + return Err(TypeError::VariadicMismatch( + expected_found(relation, &a.variadic, &b.variadic))); + } + + let inputs = relate_arg_vecs(relation, + &a.inputs, + &b.inputs)?; + + let output = match (a.output, b.output) { + (ty::FnConverging(a_ty), ty::FnConverging(b_ty)) => + Ok(ty::FnConverging(relation.relate(&a_ty, &b_ty)?)), + (ty::FnDiverging, ty::FnDiverging) => + Ok(ty::FnDiverging), + (a, b) => + Err(TypeError::ConvergenceMismatch( + expected_found(relation, &(a != ty::FnDiverging), &(b != ty::FnDiverging)))), + }?; + + return Ok(ty::FnSig {inputs: inputs, + output: output, + variadic: a.variadic}); + } +} + +fn relate_arg_vecs<'a,'tcx:'a,R>(relation: &mut R, + a_args: &[Ty<'tcx>], + b_args: &[Ty<'tcx>]) + -> RelateResult<'tcx, Vec>> + where R: TypeRelation<'a,'tcx> +{ + if a_args.len() != b_args.len() { + return Err(TypeError::ArgCount); + } + + a_args.iter().zip(b_args) + .map(|(a, b)| relation.relate_with_variance(ty::Contravariant, a, b)) + .collect() +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ast::Unsafety { + fn relate(relation: &mut R, + a: &ast::Unsafety, + b: &ast::Unsafety) + -> RelateResult<'tcx, ast::Unsafety> + where R: TypeRelation<'a,'tcx> + { + if a != b { + Err(TypeError::UnsafetyMismatch(expected_found(relation, a, b))) + } else { + Ok(*a) + } + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for abi::Abi { + fn relate(relation: &mut R, + a: &abi::Abi, + b: &abi::Abi) + -> RelateResult<'tcx, abi::Abi> + where R: TypeRelation<'a,'tcx> + { + if a == b { + Ok(*a) + } else { + Err(TypeError::AbiMismatch(expected_found(relation, a, b))) + } + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ProjectionTy<'tcx> { + fn relate(relation: &mut R, + a: &ty::ProjectionTy<'tcx>, + b: &ty::ProjectionTy<'tcx>) + -> RelateResult<'tcx, ty::ProjectionTy<'tcx>> + where R: TypeRelation<'a,'tcx> + { + if a.item_name != b.item_name { + Err(TypeError::ProjectionNameMismatched( + expected_found(relation, &a.item_name, &b.item_name))) + } else { + let trait_ref = relation.relate(&a.trait_ref, &b.trait_ref)?; + Ok(ty::ProjectionTy { trait_ref: trait_ref, item_name: a.item_name }) + } + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ProjectionPredicate<'tcx> { + fn relate(relation: &mut R, + a: &ty::ProjectionPredicate<'tcx>, + b: &ty::ProjectionPredicate<'tcx>) + -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> + where R: TypeRelation<'a,'tcx> + { + let projection_ty = relation.relate(&a.projection_ty, &b.projection_ty)?; + let ty = relation.relate(&a.ty, &b.ty)?; + Ok(ty::ProjectionPredicate { projection_ty: projection_ty, ty: ty }) + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for Vec> { + fn relate(relation: &mut R, + a: &Vec>, + b: &Vec>) + -> RelateResult<'tcx, Vec>> + where R: TypeRelation<'a,'tcx> + { + // To be compatible, `a` and `b` must be for precisely the + // same set of traits and item names. We always require that + // projection bounds lists are sorted by trait-def-id and item-name, + // so we can just iterate through the lists pairwise, so long as they are the + // same length. + if a.len() != b.len() { + Err(TypeError::ProjectionBoundsLength(expected_found(relation, &a.len(), &b.len()))) + } else { + a.iter().zip(b) + .map(|(a, b)| relation.relate(a, b)) + .collect() + } + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ExistentialBounds<'tcx> { + fn relate(relation: &mut R, + a: &ty::ExistentialBounds<'tcx>, + b: &ty::ExistentialBounds<'tcx>) + -> RelateResult<'tcx, ty::ExistentialBounds<'tcx>> + where R: TypeRelation<'a,'tcx> + { + let r = + relation.with_cause( + Cause::ExistentialRegionBound, + |relation| relation.relate_with_variance(ty::Contravariant, + &a.region_bound, + &b.region_bound))?; + let nb = relation.relate(&a.builtin_bounds, &b.builtin_bounds)?; + let pb = relation.relate(&a.projection_bounds, &b.projection_bounds)?; + Ok(ty::ExistentialBounds { region_bound: r, + builtin_bounds: nb, + projection_bounds: pb }) + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::BuiltinBounds { + fn relate(relation: &mut R, + a: &ty::BuiltinBounds, + b: &ty::BuiltinBounds) + -> RelateResult<'tcx, ty::BuiltinBounds> + where R: TypeRelation<'a,'tcx> + { + // Two sets of builtin bounds are only relatable if they are + // precisely the same (but see the coercion code). + if a != b { + Err(TypeError::BuiltinBoundsMismatch(expected_found(relation, a, b))) + } else { + Ok(*a) + } + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::TraitRef<'tcx> { + fn relate(relation: &mut R, + a: &ty::TraitRef<'tcx>, + b: &ty::TraitRef<'tcx>) + -> RelateResult<'tcx, ty::TraitRef<'tcx>> + where R: TypeRelation<'a,'tcx> + { + // Different traits cannot be related + if a.def_id != b.def_id { + Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id))) + } else { + let substs = relate_item_substs(relation, a.def_id, a.substs, b.substs)?; + Ok(ty::TraitRef { def_id: a.def_id, substs: relation.tcx().mk_substs(substs) }) + } + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for Ty<'tcx> { + fn relate(relation: &mut R, + a: &Ty<'tcx>, + b: &Ty<'tcx>) + -> RelateResult<'tcx, Ty<'tcx>> + where R: TypeRelation<'a,'tcx> + { + relation.tys(a, b) + } +} + +/// The main "type relation" routine. Note that this does not handle +/// inference artifacts, so you should filter those out before calling +/// it. +pub fn super_relate_tys<'a,'tcx:'a,R>(relation: &mut R, + a: Ty<'tcx>, + b: Ty<'tcx>) + -> RelateResult<'tcx, Ty<'tcx>> + where R: TypeRelation<'a,'tcx> +{ + let tcx = relation.tcx(); + let a_sty = &a.sty; + let b_sty = &b.sty; + debug!("super_tys: a_sty={:?} b_sty={:?}", a_sty, b_sty); + match (a_sty, b_sty) { + (&ty::TyInfer(_), _) | + (_, &ty::TyInfer(_)) => + { + // The caller should handle these cases! + tcx.sess.bug("var types encountered in super_relate_tys") + } + + (&ty::TyError, _) | (_, &ty::TyError) => + { + Ok(tcx.types.err) + } + + (&ty::TyChar, _) | + (&ty::TyBool, _) | + (&ty::TyInt(_), _) | + (&ty::TyUint(_), _) | + (&ty::TyFloat(_), _) | + (&ty::TyStr, _) + if a == b => + { + Ok(a) + } + + (&ty::TyParam(ref a_p), &ty::TyParam(ref b_p)) + if a_p.idx == b_p.idx && a_p.space == b_p.space => + { + Ok(a) + } + + (&ty::TyEnum(a_def, a_substs), &ty::TyEnum(b_def, b_substs)) + if a_def == b_def => + { + let substs = relate_item_substs(relation, a_def.did, a_substs, b_substs)?; + Ok(tcx.mk_enum(a_def, tcx.mk_substs(substs))) + } + + (&ty::TyTrait(ref a_), &ty::TyTrait(ref b_)) => + { + let principal = relation.relate(&a_.principal, &b_.principal)?; + let bounds = relation.relate(&a_.bounds, &b_.bounds)?; + Ok(tcx.mk_trait(principal, bounds)) + } + + (&ty::TyStruct(a_def, a_substs), &ty::TyStruct(b_def, b_substs)) + if a_def == b_def => + { + let substs = relate_item_substs(relation, a_def.did, a_substs, b_substs)?; + Ok(tcx.mk_struct(a_def, tcx.mk_substs(substs))) + } + + (&ty::TyClosure(a_id, ref a_substs), + &ty::TyClosure(b_id, ref b_substs)) + if a_id == b_id => + { + // All TyClosure types with the same id represent + // the (anonymous) type of the same closure expression. So + // all of their regions should be equated. + let substs = relation.relate(a_substs, b_substs)?; + Ok(tcx.mk_closure_from_closure_substs(a_id, substs)) + } + + (&ty::TyBox(a_inner), &ty::TyBox(b_inner)) => + { + let typ = relation.relate(&a_inner, &b_inner)?; + Ok(tcx.mk_box(typ)) + } + + (&ty::TyRawPtr(ref a_mt), &ty::TyRawPtr(ref b_mt)) => + { + let mt = relation.relate(a_mt, b_mt)?; + Ok(tcx.mk_ptr(mt)) + } + + (&ty::TyRef(a_r, ref a_mt), &ty::TyRef(b_r, ref b_mt)) => + { + let r = relation.relate_with_variance(ty::Contravariant, a_r, b_r)?; + let mt = relation.relate(a_mt, b_mt)?; + Ok(tcx.mk_ref(tcx.mk_region(r), mt)) + } + + (&ty::TyArray(a_t, sz_a), &ty::TyArray(b_t, sz_b)) => + { + let t = relation.relate(&a_t, &b_t)?; + if sz_a == sz_b { + Ok(tcx.mk_array(t, sz_a)) + } else { + Err(TypeError::FixedArraySize(expected_found(relation, &sz_a, &sz_b))) + } + } + + (&ty::TySlice(a_t), &ty::TySlice(b_t)) => + { + let t = relation.relate(&a_t, &b_t)?; + Ok(tcx.mk_slice(t)) + } + + (&ty::TyTuple(ref as_), &ty::TyTuple(ref bs)) => + { + if as_.len() == bs.len() { + let ts = as_.iter().zip(bs) + .map(|(a, b)| relation.relate(a, b)) + .collect::>()?; + Ok(tcx.mk_tup(ts)) + } else if !(as_.is_empty() || bs.is_empty()) { + Err(TypeError::TupleSize( + expected_found(relation, &as_.len(), &bs.len()))) + } else { + Err(TypeError::Sorts(expected_found(relation, &a, &b))) + } + } + + (&ty::TyFnDef(a_def_id, a_substs, a_fty), + &ty::TyFnDef(b_def_id, b_substs, b_fty)) + if a_def_id == b_def_id => + { + let substs = relate_substs(relation, None, a_substs, b_substs)?; + let fty = relation.relate(a_fty, b_fty)?; + Ok(tcx.mk_fn_def(a_def_id, tcx.mk_substs(substs), fty)) + } + + (&ty::TyFnPtr(a_fty), &ty::TyFnPtr(b_fty)) => + { + let fty = relation.relate(a_fty, b_fty)?; + Ok(tcx.mk_fn_ptr(fty)) + } + + (&ty::TyProjection(ref a_data), &ty::TyProjection(ref b_data)) => + { + let projection_ty = relation.relate(a_data, b_data)?; + Ok(tcx.mk_projection(projection_ty.trait_ref, projection_ty.item_name)) + } + + _ => + { + Err(TypeError::Sorts(expected_found(relation, &a, &b))) + } + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ClosureSubsts<'tcx> { + fn relate(relation: &mut R, + a: &ty::ClosureSubsts<'tcx>, + b: &ty::ClosureSubsts<'tcx>) + -> RelateResult<'tcx, ty::ClosureSubsts<'tcx>> + where R: TypeRelation<'a,'tcx> + { + let func_substs = relate_substs(relation, None, a.func_substs, b.func_substs)?; + let upvar_tys = relation.relate_zip(&a.upvar_tys, &b.upvar_tys)?; + Ok(ty::ClosureSubsts { func_substs: relation.tcx().mk_substs(func_substs), + upvar_tys: upvar_tys }) + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::Region { + fn relate(relation: &mut R, + a: &ty::Region, + b: &ty::Region) + -> RelateResult<'tcx, ty::Region> + where R: TypeRelation<'a,'tcx> + { + relation.regions(*a, *b) + } +} + +impl<'a,'tcx:'a,T> Relate<'a,'tcx> for ty::Binder + where T: Relate<'a,'tcx> +{ + fn relate(relation: &mut R, + a: &ty::Binder, + b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where R: TypeRelation<'a,'tcx> + { + relation.binders(a, b) + } +} + +impl<'a,'tcx:'a,T> Relate<'a,'tcx> for Rc + where T: Relate<'a,'tcx> +{ + fn relate(relation: &mut R, + a: &Rc, + b: &Rc) + -> RelateResult<'tcx, Rc> + where R: TypeRelation<'a,'tcx> + { + let a: &T = a; + let b: &T = b; + Ok(Rc::new(relation.relate(a, b)?)) + } +} + +impl<'a,'tcx:'a,T> Relate<'a,'tcx> for Box + where T: Relate<'a,'tcx> +{ + fn relate(relation: &mut R, + a: &Box, + b: &Box) + -> RelateResult<'tcx, Box> + where R: TypeRelation<'a,'tcx> + { + let a: &T = a; + let b: &T = b; + Ok(Box::new(relation.relate(a, b)?)) + } +} + +/////////////////////////////////////////////////////////////////////////// +// Error handling + +pub fn expected_found<'a,'tcx:'a,R,T>(relation: &mut R, + a: &T, + b: &T) + -> ExpectedFound + where R: TypeRelation<'a,'tcx>, T: Clone +{ + expected_found_bool(relation.a_is_expected(), a, b) +} + +pub fn expected_found_bool(a_is_expected: bool, + a: &T, + b: &T) + -> ExpectedFound + where T: Clone +{ + let a = a.clone(); + let b = b.clone(); + if a_is_expected { + ExpectedFound {expected: a, found: b} + } else { + ExpectedFound {expected: b, found: a} + } +} diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs new file mode 100644 index 00000000000..6fca1eef701 --- /dev/null +++ b/src/librustc/ty/structural_impls.rs @@ -0,0 +1,815 @@ +// Copyright 2012-2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ty::subst::{self, VecPerParamSpace}; +use traits; +use ty::{self, Lift, TraitRef, Ty, TyCtxt}; +use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; + +use std::rc::Rc; +use syntax::abi; +use syntax::ptr::P; + +use rustc_front::hir; + +/////////////////////////////////////////////////////////////////////////// +// Lift implementations + +impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>> Lift<'tcx> for (A, B) { + type Lifted = (A::Lifted, B::Lifted); + fn lift_to_tcx(&self, tcx: &TyCtxt<'tcx>) -> Option { + tcx.lift(&self.0).and_then(|a| tcx.lift(&self.1).map(|b| (a, b))) + } +} + +impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for [T] { + type Lifted = Vec; + fn lift_to_tcx(&self, tcx: &TyCtxt<'tcx>) -> Option { + // type annotation needed to inform `projection_must_outlive` + let mut result : Vec<>::Lifted> + = Vec::with_capacity(self.len()); + for x in self { + if let Some(value) = tcx.lift(x) { + result.push(value); + } else { + return None; + } + } + Some(result) + } +} + +impl<'tcx> Lift<'tcx> for ty::Region { + type Lifted = Self; + fn lift_to_tcx(&self, _: &TyCtxt<'tcx>) -> Option { + Some(*self) + } +} + +impl<'a, 'tcx> Lift<'tcx> for TraitRef<'a> { + type Lifted = TraitRef<'tcx>; + fn lift_to_tcx(&self, tcx: &TyCtxt<'tcx>) -> Option> { + tcx.lift(&self.substs).map(|substs| TraitRef { + def_id: self.def_id, + substs: substs + }) + } +} + +impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> { + type Lifted = ty::TraitPredicate<'tcx>; + fn lift_to_tcx(&self, tcx: &TyCtxt<'tcx>) -> Option> { + tcx.lift(&self.trait_ref).map(|trait_ref| ty::TraitPredicate { + trait_ref: trait_ref + }) + } +} + +impl<'a, 'tcx> Lift<'tcx> for ty::EquatePredicate<'a> { + type Lifted = ty::EquatePredicate<'tcx>; + fn lift_to_tcx(&self, tcx: &TyCtxt<'tcx>) -> Option> { + tcx.lift(&(self.0, self.1)).map(|(a, b)| ty::EquatePredicate(a, b)) + } +} + +impl<'tcx, A: Copy+Lift<'tcx>, B: Copy+Lift<'tcx>> Lift<'tcx> for ty::OutlivesPredicate { + type Lifted = ty::OutlivesPredicate; + fn lift_to_tcx(&self, tcx: &TyCtxt<'tcx>) -> Option { + tcx.lift(&(self.0, self.1)).map(|(a, b)| ty::OutlivesPredicate(a, b)) + } +} + +impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionPredicate<'a> { + type Lifted = ty::ProjectionPredicate<'tcx>; + fn lift_to_tcx(&self, tcx: &TyCtxt<'tcx>) -> Option> { + tcx.lift(&(self.projection_ty.trait_ref, self.ty)).map(|(trait_ref, ty)| { + ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy { + trait_ref: trait_ref, + item_name: self.projection_ty.item_name + }, + ty: ty + } + }) + } +} + +impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder { + type Lifted = ty::Binder; + fn lift_to_tcx(&self, tcx: &TyCtxt<'tcx>) -> Option { + tcx.lift(&self.0).map(|x| ty::Binder(x)) + } +} + +/////////////////////////////////////////////////////////////////////////// +// TypeFoldable implementations. +// +// Ideally, each type should invoke `folder.fold_foo(self)` and +// nothing else. In some cases, though, we haven't gotten around to +// adding methods on the `folder` yet, and thus the folding is +// hard-coded here. This is less-flexible, because folders cannot +// override the behavior, but there are a lot of random types and one +// can easily refactor the folding into the TypeFolder trait as +// needed. + +macro_rules! CopyImpls { + ($($ty:ty),+) => { + $( + impl<'tcx> TypeFoldable<'tcx> for $ty { + fn super_fold_with>(&self, _: &mut F) -> $ty { + *self + } + + fn super_visit_with>(&self, _: &mut F) -> bool { + false + } + } + )+ + } +} + +CopyImpls! { (), hir::Unsafety, abi::Abi } + +impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) { + fn super_fold_with>(&self, folder: &mut F) -> (T, U) { + (self.0.fold_with(folder), self.1.fold_with(folder)) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.0.visit_with(visitor) || self.1.visit_with(visitor) + } +} + +impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Option { + fn super_fold_with>(&self, folder: &mut F) -> Self { + self.as_ref().map(|t| t.fold_with(folder)) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.iter().any(|t| t.visit_with(visitor)) + } +} + +impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc { + fn super_fold_with>(&self, folder: &mut F) -> Self { + Rc::new((**self).fold_with(folder)) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + (**self).visit_with(visitor) + } +} + +impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box { + fn super_fold_with>(&self, folder: &mut F) -> Self { + let content: T = (**self).fold_with(folder); + box content + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + (**self).visit_with(visitor) + } +} + +impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec { + fn super_fold_with>(&self, folder: &mut F) -> Self { + self.iter().map(|t| t.fold_with(folder)).collect() + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.iter().any(|t| t.visit_with(visitor)) + } +} + +impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder { + fn super_fold_with>(&self, folder: &mut F) -> Self { + folder.enter_region_binder(); + let result = ty::Binder(self.0.fold_with(folder)); + folder.exit_region_binder(); + result + } + + fn fold_with>(&self, folder: &mut F) -> Self { + folder.fold_binder(self) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + visitor.enter_region_binder(); + if self.0.visit_with(visitor) { return true } + visitor.exit_region_binder(); + false + } +} + +impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for P<[T]> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + self.iter().map(|t| t.fold_with(folder)).collect() + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.iter().any(|t| t.visit_with(visitor)) + } +} + +impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for VecPerParamSpace { + fn super_fold_with>(&self, folder: &mut F) -> Self { + + // Things in the Fn space take place under an additional level + // of region binding relative to the other spaces. This is + // because those entries are attached to a method, and methods + // always introduce a level of region binding. + + let result = self.map_enumerated(|(space, index, elem)| { + if space == subst::FnSpace && index == 0 { + // enter new level when/if we reach the first thing in fn space + folder.enter_region_binder(); + } + elem.fold_with(folder) + }); + if result.len(subst::FnSpace) > 0 { + // if there was anything in fn space, exit the region binding level + folder.exit_region_binder(); + } + result + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + let mut entered_region_binder = false; + let result = self.iter_enumerated().any(|(space, index, t)| { + if space == subst::FnSpace && index == 0 { + visitor.enter_region_binder(); + entered_region_binder = true; + } + t.visit_with(visitor) + }); + if entered_region_binder { + visitor.exit_region_binder(); + } + result + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::TraitTy<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + ty::TraitTy { + principal: self.principal.fold_with(folder), + bounds: self.bounds.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.principal.visit_with(visitor) || self.bounds.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + let sty = match self.sty { + ty::TyBox(typ) => ty::TyBox(typ.fold_with(folder)), + ty::TyRawPtr(ref tm) => ty::TyRawPtr(tm.fold_with(folder)), + ty::TyArray(typ, sz) => ty::TyArray(typ.fold_with(folder), sz), + ty::TySlice(typ) => ty::TySlice(typ.fold_with(folder)), + ty::TyEnum(tid, ref substs) => { + let substs = substs.fold_with(folder); + ty::TyEnum(tid, folder.tcx().mk_substs(substs)) + } + ty::TyTrait(ref trait_ty) => ty::TyTrait(trait_ty.fold_with(folder)), + ty::TyTuple(ref ts) => ty::TyTuple(ts.fold_with(folder)), + ty::TyFnDef(def_id, substs, ref f) => { + let substs = substs.fold_with(folder); + let bfn = f.fold_with(folder); + ty::TyFnDef(def_id, + folder.tcx().mk_substs(substs), + folder.tcx().mk_bare_fn(bfn)) + } + ty::TyFnPtr(ref f) => { + let bfn = f.fold_with(folder); + ty::TyFnPtr(folder.tcx().mk_bare_fn(bfn)) + } + ty::TyRef(r, ref tm) => { + let r = r.fold_with(folder); + ty::TyRef(folder.tcx().mk_region(r), tm.fold_with(folder)) + } + ty::TyStruct(did, ref substs) => { + let substs = substs.fold_with(folder); + ty::TyStruct(did, folder.tcx().mk_substs(substs)) + } + ty::TyClosure(did, ref substs) => { + ty::TyClosure(did, substs.fold_with(folder)) + } + ty::TyProjection(ref data) => ty::TyProjection(data.fold_with(folder)), + ty::TyBool | ty::TyChar | ty::TyStr | ty::TyInt(_) | + ty::TyUint(_) | ty::TyFloat(_) | ty::TyError | ty::TyInfer(_) | + ty::TyParam(..) => self.sty.clone(), + }; + folder.tcx().mk_ty(sty) + } + + fn fold_with>(&self, folder: &mut F) -> Self { + folder.fold_ty(*self) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + match self.sty { + ty::TyBox(typ) => typ.visit_with(visitor), + ty::TyRawPtr(ref tm) => tm.visit_with(visitor), + ty::TyArray(typ, _sz) => typ.visit_with(visitor), + ty::TySlice(typ) => typ.visit_with(visitor), + ty::TyEnum(_tid, ref substs) => substs.visit_with(visitor), + ty::TyTrait(ref trait_ty) => trait_ty.visit_with(visitor), + ty::TyTuple(ref ts) => ts.visit_with(visitor), + ty::TyFnDef(_, substs, ref f) => { + substs.visit_with(visitor) || f.visit_with(visitor) + } + ty::TyFnPtr(ref f) => f.visit_with(visitor), + ty::TyRef(r, ref tm) => r.visit_with(visitor) || tm.visit_with(visitor), + ty::TyStruct(_did, ref substs) => substs.visit_with(visitor), + ty::TyClosure(_did, ref substs) => substs.visit_with(visitor), + ty::TyProjection(ref data) => data.visit_with(visitor), + ty::TyBool | ty::TyChar | ty::TyStr | ty::TyInt(_) | + ty::TyUint(_) | ty::TyFloat(_) | ty::TyError | ty::TyInfer(_) | + ty::TyParam(..) => false, + } + } + + fn visit_with>(&self, visitor: &mut V) -> bool { + visitor.visit_ty(self) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::BareFnTy<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + ty::BareFnTy { sig: self.sig.fold_with(folder), + abi: self.abi, + unsafety: self.unsafety } + } + + fn fold_with>(&self, folder: &mut F) -> Self { + folder.fold_bare_fn_ty(self) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.sig.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::ClosureTy<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + ty::ClosureTy { + sig: self.sig.fold_with(folder), + unsafety: self.unsafety, + abi: self.abi, + } + } + + fn fold_with>(&self, folder: &mut F) -> Self { + folder.fold_closure_ty(self) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.sig.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + ty::TypeAndMut { ty: self.ty.fold_with(folder), mutbl: self.mutbl } + } + + fn fold_with>(&self, folder: &mut F) -> Self { + folder.fold_mt(self) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.ty.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::FnOutput<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + match *self { + ty::FnConverging(ref ty) => ty::FnConverging(ty.fold_with(folder)), + ty::FnDiverging => ty::FnDiverging + } + } + + fn fold_with>(&self, folder: &mut F) -> Self { + folder.fold_output(self) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + match *self { + ty::FnConverging(ref ty) => ty.visit_with(visitor), + ty::FnDiverging => false, + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + ty::FnSig { inputs: self.inputs.fold_with(folder), + output: self.output.fold_with(folder), + variadic: self.variadic } + } + + fn fold_with>(&self, folder: &mut F) -> Self { + folder.fold_fn_sig(self) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.inputs.visit_with(visitor) || self.output.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::TraitRef<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + let substs = self.substs.fold_with(folder); + ty::TraitRef { + def_id: self.def_id, + substs: folder.tcx().mk_substs(substs), + } + } + + fn fold_with>(&self, folder: &mut F) -> Self { + folder.fold_trait_ref(self) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.substs.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::ImplHeader<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + ty::ImplHeader { + impl_def_id: self.impl_def_id, + self_ty: self.self_ty.fold_with(folder), + trait_ref: self.trait_ref.map(|t| t.fold_with(folder)), + predicates: self.predicates.iter().map(|p| p.fold_with(folder)).collect(), + } + } + + fn fold_with>(&self, folder: &mut F) -> Self { + folder.fold_impl_header(self) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.self_ty.visit_with(visitor) || + self.trait_ref.map(|r| r.visit_with(visitor)).unwrap_or(false) || + self.predicates.iter().any(|p| p.visit_with(visitor)) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::Region { + fn super_fold_with>(&self, _folder: &mut F) -> Self { + *self + } + + fn fold_with>(&self, folder: &mut F) -> Self { + folder.fold_region(*self) + } + + fn super_visit_with>(&self, _visitor: &mut V) -> bool { + false + } + + fn visit_with>(&self, visitor: &mut V) -> bool { + visitor.visit_region(*self) + } +} + +impl<'tcx> TypeFoldable<'tcx> for subst::Substs<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + subst::Substs { regions: self.regions.fold_with(folder), + types: self.types.fold_with(folder) } + } + + fn fold_with>(&self, folder: &mut F) -> Self { + folder.fold_substs(self) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.types.visit_with(visitor) || self.regions.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + let func_substs = self.func_substs.fold_with(folder); + ty::ClosureSubsts { + func_substs: folder.tcx().mk_substs(func_substs), + upvar_tys: self.upvar_tys.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.func_substs.visit_with(visitor) || self.upvar_tys.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::ItemSubsts<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + ty::ItemSubsts { + substs: self.substs.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.substs.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoRef<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + match *self { + ty::adjustment::AutoPtr(r, m) => { + let r = r.fold_with(folder); + ty::adjustment::AutoPtr(folder.tcx().mk_region(r), m) + } + ty::adjustment::AutoUnsafe(m) => ty::adjustment::AutoUnsafe(m) + } + } + + fn fold_with>(&self, folder: &mut F) -> Self { + folder.fold_autoref(self) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + match *self { + ty::adjustment::AutoPtr(r, _m) => r.visit_with(visitor), + ty::adjustment::AutoUnsafe(_m) => false, + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::BuiltinBounds { + fn super_fold_with>(&self, _folder: &mut F) -> Self { + *self + } + + fn super_visit_with>(&self, _visitor: &mut V) -> bool { + false + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialBounds<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + ty::ExistentialBounds { + region_bound: self.region_bound.fold_with(folder), + builtin_bounds: self.builtin_bounds, + projection_bounds: self.projection_bounds.fold_with(folder), + } + } + + fn fold_with>(&self, folder: &mut F) -> Self { + folder.fold_existential_bounds(self) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.region_bound.visit_with(visitor) || self.projection_bounds.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + ty::TypeParameterDef { + name: self.name, + def_id: self.def_id, + space: self.space, + index: self.index, + default: self.default.fold_with(folder), + default_def_id: self.default_def_id, + object_lifetime_default: self.object_lifetime_default.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.default.visit_with(visitor) || + self.object_lifetime_default.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::ObjectLifetimeDefault { + fn super_fold_with>(&self, folder: &mut F) -> Self { + match *self { + ty::ObjectLifetimeDefault::Ambiguous => + ty::ObjectLifetimeDefault::Ambiguous, + + ty::ObjectLifetimeDefault::BaseDefault => + ty::ObjectLifetimeDefault::BaseDefault, + + ty::ObjectLifetimeDefault::Specific(r) => + ty::ObjectLifetimeDefault::Specific(r.fold_with(folder)), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + match *self { + ty::ObjectLifetimeDefault::Specific(r) => r.visit_with(visitor), + _ => false, + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef { + fn super_fold_with>(&self, folder: &mut F) -> Self { + ty::RegionParameterDef { + name: self.name, + def_id: self.def_id, + space: self.space, + index: self.index, + bounds: self.bounds.fold_with(folder) + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.bounds.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::Generics<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + ty::Generics { + types: self.types.fold_with(folder), + regions: self.regions.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.types.visit_with(visitor) || self.regions.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::GenericPredicates<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + ty::GenericPredicates { + predicates: self.predicates.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.predicates.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + match *self { + ty::Predicate::Trait(ref a) => + ty::Predicate::Trait(a.fold_with(folder)), + ty::Predicate::Equate(ref binder) => + ty::Predicate::Equate(binder.fold_with(folder)), + ty::Predicate::RegionOutlives(ref binder) => + ty::Predicate::RegionOutlives(binder.fold_with(folder)), + ty::Predicate::TypeOutlives(ref binder) => + ty::Predicate::TypeOutlives(binder.fold_with(folder)), + ty::Predicate::Projection(ref binder) => + ty::Predicate::Projection(binder.fold_with(folder)), + ty::Predicate::WellFormed(data) => + ty::Predicate::WellFormed(data.fold_with(folder)), + ty::Predicate::ObjectSafe(trait_def_id) => + ty::Predicate::ObjectSafe(trait_def_id), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + match *self { + ty::Predicate::Trait(ref a) => a.visit_with(visitor), + ty::Predicate::Equate(ref binder) => binder.visit_with(visitor), + ty::Predicate::RegionOutlives(ref binder) => binder.visit_with(visitor), + ty::Predicate::TypeOutlives(ref binder) => binder.visit_with(visitor), + ty::Predicate::Projection(ref binder) => binder.visit_with(visitor), + ty::Predicate::WellFormed(data) => data.visit_with(visitor), + ty::Predicate::ObjectSafe(_trait_def_id) => false, + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionPredicate<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + ty::ProjectionPredicate { + projection_ty: self.projection_ty.fold_with(folder), + ty: self.ty.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.projection_ty.visit_with(visitor) || self.ty.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionTy<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + ty::ProjectionTy { + trait_ref: self.trait_ref.fold_with(folder), + item_name: self.item_name, + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.trait_ref.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::InstantiatedPredicates<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + ty::InstantiatedPredicates { + predicates: self.predicates.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.predicates.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + ty::EquatePredicate(self.0.fold_with(folder), + self.1.fold_with(folder)) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.0.visit_with(visitor) || self.1.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::TraitPredicate<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + ty::TraitPredicate { + trait_ref: self.trait_ref.fold_with(folder) + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.trait_ref.visit_with(visitor) + } +} + +impl<'tcx,T,U> TypeFoldable<'tcx> for ty::OutlivesPredicate + where T : TypeFoldable<'tcx>, + U : TypeFoldable<'tcx>, +{ + fn super_fold_with>(&self, folder: &mut F) -> Self { + ty::OutlivesPredicate(self.0.fold_with(folder), + self.1.fold_with(folder)) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.0.visit_with(visitor) || self.1.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::ClosureUpvar<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + ty::ClosureUpvar { + def: self.def, + span: self.span, + ty: self.ty.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.ty.visit_with(visitor) + } +} + +impl<'a, 'tcx> TypeFoldable<'tcx> for ty::ParameterEnvironment<'a, 'tcx> where 'tcx: 'a { + fn super_fold_with>(&self, folder: &mut F) -> Self { + ty::ParameterEnvironment { + tcx: self.tcx, + free_substs: self.free_substs.fold_with(folder), + implicit_region_bound: self.implicit_region_bound.fold_with(folder), + caller_bounds: self.caller_bounds.fold_with(folder), + selection_cache: traits::SelectionCache::new(), + evaluation_cache: traits::EvaluationCache::new(), + free_id_outlive: self.free_id_outlive, + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.free_substs.visit_with(visitor) || + self.implicit_region_bound.visit_with(visitor) || + self.caller_bounds.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::TypeScheme<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + ty::TypeScheme { + generics: self.generics.fold_with(folder), + ty: self.ty.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.generics.visit_with(visitor) || self.ty.visit_with(visitor) + } +} diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs new file mode 100644 index 00000000000..dae12824da2 --- /dev/null +++ b/src/librustc/ty/sty.rs @@ -0,0 +1,1240 @@ +// Copyright 2012-2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module contains TypeVariants and its major components + +use middle::cstore; +use middle::def_id::DefId; +use middle::region; +use ty::subst::{self, Substs}; +use traits; +use ty::{self, AdtDef, ToPredicate, TypeFlags, Ty, TyCtxt, TyS, TypeFoldable}; +use util::common::ErrorReported; + +use collections::enum_set::{self, EnumSet, CLike}; +use std::fmt; +use std::ops; +use std::mem; +use syntax::abi; +use syntax::ast::{self, Name}; +use syntax::parse::token::special_idents; + +use serialize::{Decodable, Decoder}; + +use rustc_front::hir; + +use self::FnOutput::*; +use self::InferTy::*; +use self::TypeVariants::*; + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub struct TypeAndMut<'tcx> { + pub ty: Ty<'tcx>, + pub mutbl: hir::Mutability, +} + +#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, + RustcEncodable, RustcDecodable, Copy)] +/// A "free" region `fr` can be interpreted as "some region +/// at least as big as the scope `fr.scope`". +pub struct FreeRegion { + pub scope: region::CodeExtent, + pub bound_region: BoundRegion +} + +#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, + RustcEncodable, RustcDecodable, Copy)] +pub enum BoundRegion { + /// An anonymous region parameter for a given fn (&T) + BrAnon(u32), + + /// Named region parameters for functions (a in &'a T) + /// + /// The def-id is needed to distinguish free regions in + /// the event of shadowing. + BrNamed(DefId, Name), + + /// Fresh bound identifiers created during GLB computations. + BrFresh(u32), + + // Anonymous region for the implicit env pointer parameter + // to a closure + BrEnv +} + +// NB: If you change this, you'll probably want to change the corresponding +// AST structure in libsyntax/ast.rs as well. +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub enum TypeVariants<'tcx> { + /// The primitive boolean type. Written as `bool`. + TyBool, + + /// The primitive character type; holds a Unicode scalar value + /// (a non-surrogate code point). Written as `char`. + TyChar, + + /// A primitive signed integer type. For example, `i32`. + TyInt(ast::IntTy), + + /// A primitive unsigned integer type. For example, `u32`. + TyUint(ast::UintTy), + + /// A primitive floating-point type. For example, `f64`. + TyFloat(ast::FloatTy), + + /// An enumerated type, defined with `enum`. + /// + /// Substs here, possibly against intuition, *may* contain `TyParam`s. + /// That is, even after substitution it is possible that there are type + /// variables. This happens when the `TyEnum` corresponds to an enum + /// definition and not a concrete use of it. To get the correct `TyEnum` + /// from the tcx, use the `NodeId` from the `ast::Ty` and look it up in + /// the `ast_ty_to_ty_cache`. This is probably true for `TyStruct` as + /// well. + TyEnum(AdtDef<'tcx>, &'tcx Substs<'tcx>), + + /// A structure type, defined with `struct`. + /// + /// See warning about substitutions for enumerated types. + TyStruct(AdtDef<'tcx>, &'tcx Substs<'tcx>), + + /// `Box`; this is nominally a struct in the documentation, but is + /// special-cased internally. For example, it is possible to implicitly + /// move the contents of a box out of that box, and methods of any type + /// can have type `Box`. + TyBox(Ty<'tcx>), + + /// The pointee of a string slice. Written as `str`. + TyStr, + + /// An array with the given length. Written as `[T; n]`. + TyArray(Ty<'tcx>, usize), + + /// The pointee of an array slice. Written as `[T]`. + TySlice(Ty<'tcx>), + + /// A raw pointer. Written as `*mut T` or `*const T` + TyRawPtr(TypeAndMut<'tcx>), + + /// A reference; a pointer with an associated lifetime. Written as + /// `&a mut T` or `&'a T`. + TyRef(&'tcx Region, TypeAndMut<'tcx>), + + /// The anonymous type of a function declaration/definition. Each + /// function has a unique type. + TyFnDef(DefId, &'tcx Substs<'tcx>, &'tcx BareFnTy<'tcx>), + + /// A pointer to a function. Written as `fn() -> i32`. + /// FIXME: This is currently also used to represent the callee of a method; + /// see ty::MethodCallee etc. + TyFnPtr(&'tcx BareFnTy<'tcx>), + + /// A trait, defined with `trait`. + TyTrait(Box>), + + /// The anonymous type of a closure. Used to represent the type of + /// `|a| a`. + TyClosure(DefId, Box>), + + /// A tuple type. For example, `(i32, bool)`. + TyTuple(Vec>), + + /// The projection of an associated type. For example, + /// `>::N`. + TyProjection(ProjectionTy<'tcx>), + + /// A type parameter; for example, `T` in `fn f(x: T) {} + TyParam(ParamTy), + + /// A type variable used during type-checking. + TyInfer(InferTy), + + /// A placeholder for a type which could not be computed; this is + /// propagated to avoid useless error messages. + TyError, +} + +/// A closure can be modeled as a struct that looks like: +/// +/// struct Closure<'l0...'li, T0...Tj, U0...Uk> { +/// upvar0: U0, +/// ... +/// upvark: Uk +/// } +/// +/// where 'l0...'li and T0...Tj are the lifetime and type parameters +/// in scope on the function that defined the closure, and U0...Uk are +/// type parameters representing the types of its upvars (borrowed, if +/// appropriate). +/// +/// So, for example, given this function: +/// +/// fn foo<'a, T>(data: &'a mut T) { +/// do(|| data.count += 1) +/// } +/// +/// the type of the closure would be something like: +/// +/// struct Closure<'a, T, U0> { +/// data: U0 +/// } +/// +/// Note that the type of the upvar is not specified in the struct. +/// You may wonder how the impl would then be able to use the upvar, +/// if it doesn't know it's type? The answer is that the impl is +/// (conceptually) not fully generic over Closure but rather tied to +/// instances with the expected upvar types: +/// +/// impl<'b, 'a, T> FnMut() for Closure<'a, T, &'b mut &'a mut T> { +/// ... +/// } +/// +/// You can see that the *impl* fully specified the type of the upvar +/// and thus knows full well that `data` has type `&'b mut &'a mut T`. +/// (Here, I am assuming that `data` is mut-borrowed.) +/// +/// Now, the last question you may ask is: Why include the upvar types +/// as extra type parameters? The reason for this design is that the +/// upvar types can reference lifetimes that are internal to the +/// creating function. In my example above, for example, the lifetime +/// `'b` represents the extent of the closure itself; this is some +/// subset of `foo`, probably just the extent of the call to the to +/// `do()`. If we just had the lifetime/type parameters from the +/// enclosing function, we couldn't name this lifetime `'b`. Note that +/// there can also be lifetimes in the types of the upvars themselves, +/// if one of them happens to be a reference to something that the +/// creating fn owns. +/// +/// OK, you say, so why not create a more minimal set of parameters +/// that just includes the extra lifetime parameters? The answer is +/// primarily that it would be hard --- we don't know at the time when +/// we create the closure type what the full types of the upvars are, +/// nor do we know which are borrowed and which are not. In this +/// design, we can just supply a fresh type parameter and figure that +/// out later. +/// +/// All right, you say, but why include the type parameters from the +/// original function then? The answer is that trans may need them +/// when monomorphizing, and they may not appear in the upvars. A +/// closure could capture no variables but still make use of some +/// in-scope type parameter with a bound (e.g., if our example above +/// had an extra `U: Default`, and the closure called `U::default()`). +/// +/// There is another reason. This design (implicitly) prohibits +/// closures from capturing themselves (except via a trait +/// object). This simplifies closure inference considerably, since it +/// means that when we infer the kind of a closure or its upvars, we +/// don't have to handle cycles where the decisions we make for +/// closure C wind up influencing the decisions we ought to make for +/// closure C (which would then require fixed point iteration to +/// handle). Plus it fixes an ICE. :P +#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +pub struct ClosureSubsts<'tcx> { + /// Lifetime and type parameters from the enclosing function. + /// These are separated out because trans wants to pass them around + /// when monomorphizing. + pub func_substs: &'tcx Substs<'tcx>, + + /// The types of the upvars. The list parallels the freevars and + /// `upvar_borrows` lists. These are kept distinct so that we can + /// easily index into them. + pub upvar_tys: Vec> +} + +impl<'tcx> Decodable for &'tcx ClosureSubsts<'tcx> { + fn decode(s: &mut S) -> Result<&'tcx ClosureSubsts<'tcx>, S::Error> { + let closure_substs = Decodable::decode(s)?; + let dummy_def_id: DefId = unsafe { mem::zeroed() }; + + cstore::tls::with_decoding_context(s, |dcx, _| { + // Intern the value + let ty = dcx.tcx().mk_closure_from_closure_substs(dummy_def_id, + Box::new(closure_substs)); + match ty.sty { + TyClosure(_, ref closure_substs) => Ok(&**closure_substs), + _ => unreachable!() + } + }) + } +} + +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct TraitTy<'tcx> { + pub principal: ty::PolyTraitRef<'tcx>, + pub bounds: ExistentialBounds<'tcx>, +} + +impl<'tcx> TraitTy<'tcx> { + pub fn principal_def_id(&self) -> DefId { + self.principal.0.def_id + } + + /// Object types don't have a self-type specified. Therefore, when + /// we convert the principal trait-ref into a normal trait-ref, + /// you must give *some* self-type. A common choice is `mk_err()` + /// or some skolemized type. + pub fn principal_trait_ref_with_self_ty(&self, + tcx: &TyCtxt<'tcx>, + self_ty: Ty<'tcx>) + -> ty::PolyTraitRef<'tcx> + { + // otherwise the escaping regions would be captured by the binder + assert!(!self_ty.has_escaping_regions()); + + ty::Binder(TraitRef { + def_id: self.principal.0.def_id, + substs: tcx.mk_substs(self.principal.0.substs.with_self_ty(self_ty)), + }) + } + + pub fn projection_bounds_with_self_ty(&self, + tcx: &TyCtxt<'tcx>, + self_ty: Ty<'tcx>) + -> Vec> + { + // otherwise the escaping regions would be captured by the binders + assert!(!self_ty.has_escaping_regions()); + + self.bounds.projection_bounds.iter() + .map(|in_poly_projection_predicate| { + let in_projection_ty = &in_poly_projection_predicate.0.projection_ty; + let substs = tcx.mk_substs(in_projection_ty.trait_ref.substs.with_self_ty(self_ty)); + let trait_ref = ty::TraitRef::new(in_projection_ty.trait_ref.def_id, + substs); + let projection_ty = ty::ProjectionTy { + trait_ref: trait_ref, + item_name: in_projection_ty.item_name + }; + ty::Binder(ty::ProjectionPredicate { + projection_ty: projection_ty, + ty: in_poly_projection_predicate.0.ty + }) + }) + .collect() + } +} + +/// A complete reference to a trait. These take numerous guises in syntax, +/// but perhaps the most recognizable form is in a where clause: +/// +/// T : Foo +/// +/// This would be represented by a trait-reference where the def-id is the +/// def-id for the trait `Foo` and the substs defines `T` as parameter 0 in the +/// `SelfSpace` and `U` as parameter 0 in the `TypeSpace`. +/// +/// Trait references also appear in object types like `Foo`, but in +/// that case the `Self` parameter is absent from the substitutions. +/// +/// Note that a `TraitRef` introduces a level of region binding, to +/// account for higher-ranked trait bounds like `T : for<'a> Foo<&'a +/// U>` or higher-ranked object types. +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct TraitRef<'tcx> { + pub def_id: DefId, + pub substs: &'tcx Substs<'tcx>, +} + +pub type PolyTraitRef<'tcx> = Binder>; + +impl<'tcx> PolyTraitRef<'tcx> { + pub fn self_ty(&self) -> Ty<'tcx> { + self.0.self_ty() + } + + pub fn def_id(&self) -> DefId { + self.0.def_id + } + + pub fn substs(&self) -> &'tcx Substs<'tcx> { + // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<> + self.0.substs + } + + pub fn input_types(&self) -> &[Ty<'tcx>] { + // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<> + self.0.input_types() + } + + pub fn to_poly_trait_predicate(&self) -> ty::PolyTraitPredicate<'tcx> { + // Note that we preserve binding levels + Binder(ty::TraitPredicate { trait_ref: self.0.clone() }) + } +} + +/// Binder is a binder for higher-ranked lifetimes. It is part of the +/// compiler's representation for things like `for<'a> Fn(&'a isize)` +/// (which would be represented by the type `PolyTraitRef == +/// Binder`). Note that when we skolemize, instantiate, +/// erase, or otherwise "discharge" these bound regions, we change the +/// type from `Binder` to just `T` (see +/// e.g. `liberate_late_bound_regions`). +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct Binder(pub T); + +impl Binder { + /// Skips the binder and returns the "bound" value. This is a + /// risky thing to do because it's easy to get confused about + /// debruijn indices and the like. It is usually better to + /// discharge the binder using `no_late_bound_regions` or + /// `replace_late_bound_regions` or something like + /// that. `skip_binder` is only valid when you are either + /// extracting data that has nothing to do with bound regions, you + /// are doing some sort of test that does not involve bound + /// regions, or you are being very careful about your depth + /// accounting. + /// + /// Some examples where `skip_binder` is reasonable: + /// - extracting the def-id from a PolyTraitRef; + /// - comparing the self type of a PolyTraitRef to see if it is equal to + /// a type parameter `X`, since the type `X` does not reference any regions + pub fn skip_binder(&self) -> &T { + &self.0 + } + + pub fn as_ref(&self) -> Binder<&T> { + ty::Binder(&self.0) + } + + pub fn map_bound_ref(&self, f: F) -> Binder + where F: FnOnce(&T) -> U + { + self.as_ref().map_bound(f) + } + + pub fn map_bound(self, f: F) -> Binder + where F: FnOnce(T) -> U + { + ty::Binder(f(self.0)) + } +} + +impl fmt::Debug for TypeFlags { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.bits) + } +} + +/// Represents the projection of an associated type. In explicit UFCS +/// form this would be written `>::N`. +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct ProjectionTy<'tcx> { + /// The trait reference `T as Trait<..>`. + pub trait_ref: ty::TraitRef<'tcx>, + + /// The name `N` of the associated type. + pub item_name: Name, +} + +impl<'tcx> ProjectionTy<'tcx> { + pub fn sort_key(&self) -> (DefId, Name) { + (self.trait_ref.def_id, self.item_name) + } +} + +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct BareFnTy<'tcx> { + pub unsafety: hir::Unsafety, + pub abi: abi::Abi, + pub sig: PolyFnSig<'tcx>, +} + +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct ClosureTy<'tcx> { + pub unsafety: hir::Unsafety, + pub abi: abi::Abi, + pub sig: PolyFnSig<'tcx>, +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +pub enum FnOutput<'tcx> { + FnConverging(Ty<'tcx>), + FnDiverging +} + +impl<'tcx> FnOutput<'tcx> { + pub fn diverges(&self) -> bool { + *self == FnDiverging + } + + pub fn unwrap(self) -> Ty<'tcx> { + match self { + ty::FnConverging(t) => t, + ty::FnDiverging => unreachable!() + } + } + + pub fn unwrap_or(self, def: Ty<'tcx>) -> Ty<'tcx> { + match self { + ty::FnConverging(t) => t, + ty::FnDiverging => def + } + } +} + +pub type PolyFnOutput<'tcx> = Binder>; + +impl<'tcx> PolyFnOutput<'tcx> { + pub fn diverges(&self) -> bool { + self.0.diverges() + } +} + +/// Signature of a function type, which I have arbitrarily +/// decided to use to refer to the input/output types. +/// +/// - `inputs` is the list of arguments and their modes. +/// - `output` is the return type. +/// - `variadic` indicates whether this is a variadic function. (only true for foreign fns) +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct FnSig<'tcx> { + pub inputs: Vec>, + pub output: FnOutput<'tcx>, + pub variadic: bool +} + +pub type PolyFnSig<'tcx> = Binder>; + +impl<'tcx> PolyFnSig<'tcx> { + pub fn inputs(&self) -> ty::Binder>> { + self.map_bound_ref(|fn_sig| fn_sig.inputs.clone()) + } + pub fn input(&self, index: usize) -> ty::Binder> { + self.map_bound_ref(|fn_sig| fn_sig.inputs[index]) + } + pub fn output(&self) -> ty::Binder> { + self.map_bound_ref(|fn_sig| fn_sig.output.clone()) + } + pub fn variadic(&self) -> bool { + self.skip_binder().variadic + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct ParamTy { + pub space: subst::ParamSpace, + pub idx: u32, + pub name: Name, +} + +impl ParamTy { + pub fn new(space: subst::ParamSpace, + index: u32, + name: Name) + -> ParamTy { + ParamTy { space: space, idx: index, name: name } + } + + pub fn for_self() -> ParamTy { + ParamTy::new(subst::SelfSpace, 0, special_idents::type_self.name) + } + + pub fn for_def(def: &ty::TypeParameterDef) -> ParamTy { + ParamTy::new(def.space, def.index, def.name) + } + + pub fn to_ty<'tcx>(self, tcx: &TyCtxt<'tcx>) -> Ty<'tcx> { + tcx.mk_param(self.space, self.idx, self.name) + } + + pub fn is_self(&self) -> bool { + self.space == subst::SelfSpace && self.idx == 0 + } +} + +/// A [De Bruijn index][dbi] is a standard means of representing +/// regions (and perhaps later types) in a higher-ranked setting. In +/// particular, imagine a type like this: +/// +/// for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char) +/// ^ ^ | | | +/// | | | | | +/// | +------------+ 1 | | +/// | | | +/// +--------------------------------+ 2 | +/// | | +/// +------------------------------------------+ 1 +/// +/// In this type, there are two binders (the outer fn and the inner +/// fn). We need to be able to determine, for any given region, which +/// fn type it is bound by, the inner or the outer one. There are +/// various ways you can do this, but a De Bruijn index is one of the +/// more convenient and has some nice properties. The basic idea is to +/// count the number of binders, inside out. Some examples should help +/// clarify what I mean. +/// +/// Let's start with the reference type `&'b isize` that is the first +/// argument to the inner function. This region `'b` is assigned a De +/// Bruijn index of 1, meaning "the innermost binder" (in this case, a +/// fn). The region `'a` that appears in the second argument type (`&'a +/// isize`) would then be assigned a De Bruijn index of 2, meaning "the +/// second-innermost binder". (These indices are written on the arrays +/// in the diagram). +/// +/// What is interesting is that De Bruijn index attached to a particular +/// variable will vary depending on where it appears. For example, +/// the final type `&'a char` also refers to the region `'a` declared on +/// the outermost fn. But this time, this reference is not nested within +/// any other binders (i.e., it is not an argument to the inner fn, but +/// rather the outer one). Therefore, in this case, it is assigned a +/// De Bruijn index of 1, because the innermost binder in that location +/// is the outer fn. +/// +/// [dbi]: http://en.wikipedia.org/wiki/De_Bruijn_index +#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug, Copy)] +pub struct DebruijnIndex { + // We maintain the invariant that this is never 0. So 1 indicates + // the innermost binder. To ensure this, create with `DebruijnIndex::new`. + pub depth: u32, +} + +/// Representation of regions. +/// +/// Unlike types, most region variants are "fictitious", not concrete, +/// regions. Among these, `ReStatic`, `ReEmpty` and `ReScope` are the only +/// ones representing concrete regions. +/// +/// ## Bound Regions +/// +/// These are regions that are stored behind a binder and must be substituted +/// with some concrete region before being used. There are 2 kind of +/// bound regions: early-bound, which are bound in a TypeScheme/TraitDef, +/// and are substituted by a Substs, and late-bound, which are part of +/// higher-ranked types (e.g. `for<'a> fn(&'a ())`) and are substituted by +/// the likes of `liberate_late_bound_regions`. The distinction exists +/// because higher-ranked lifetimes aren't supported in all places. See [1][2]. +/// +/// Unlike TyParam-s, bound regions are not supposed to exist "in the wild" +/// outside their binder, e.g. in types passed to type inference, and +/// should first be substituted (by skolemized regions, free regions, +/// or region variables). +/// +/// ## Skolemized and Free Regions +/// +/// One often wants to work with bound regions without knowing their precise +/// identity. For example, when checking a function, the lifetime of a borrow +/// can end up being assigned to some region parameter. In these cases, +/// it must be ensured that bounds on the region can't be accidentally +/// assumed without being checked. +/// +/// The process of doing that is called "skolemization". The bound regions +/// are replaced by skolemized markers, which don't satisfy any relation +/// not explicity provided. +/// +/// There are 2 kinds of skolemized regions in rustc: `ReFree` and +/// `ReSkolemized`. When checking an item's body, `ReFree` is supposed +/// to be used. These also support explicit bounds: both the internally-stored +/// *scope*, which the region is assumed to outlive, as well as other +/// relations stored in the `FreeRegionMap`. Note that these relations +/// aren't checked when you `make_subregion` (or `mk_eqty`), only by +/// `resolve_regions_and_report_errors`. +/// +/// When working with higher-ranked types, some region relations aren't +/// yet known, so you can't just call `resolve_regions_and_report_errors`. +/// `ReSkolemized` is designed for this purpose. In these contexts, +/// there's also the risk that some inference variable laying around will +/// get unified with your skolemized region: if you want to check whether +/// `for<'a> Foo<'_>: 'a`, and you substitute your bound region `'a` +/// with a skolemized region `'%a`, the variable `'_` would just be +/// instantiated to the skolemized region `'%a`, which is wrong because +/// the inference variable is supposed to satisfy the relation +/// *for every value of the skolemized region*. To ensure that doesn't +/// happen, you can use `leak_check`. This is more clearly explained +/// by infer/higher_ranked/README.md. +/// +/// [1] http://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/ +/// [2] http://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/ +#[derive(Clone, PartialEq, Eq, Hash, Copy, RustcEncodable, RustcDecodable)] +pub enum Region { + // Region bound in a type or fn declaration which will be + // substituted 'early' -- that is, at the same time when type + // parameters are substituted. + ReEarlyBound(EarlyBoundRegion), + + // Region bound in a function scope, which will be substituted when the + // function is called. + ReLateBound(DebruijnIndex, BoundRegion), + + /// When checking a function body, the types of all arguments and so forth + /// that refer to bound region parameters are modified to refer to free + /// region parameters. + ReFree(FreeRegion), + + /// A concrete region naming some statically determined extent + /// (e.g. an expression or sequence of statements) within the + /// current function. + ReScope(region::CodeExtent), + + /// Static data that has an "infinite" lifetime. Top in the region lattice. + ReStatic, + + /// A region variable. Should not exist after typeck. + ReVar(RegionVid), + + /// A skolemized region - basically the higher-ranked version of ReFree. + /// Should not exist after typeck. + ReSkolemized(SkolemizedRegionVid, BoundRegion), + + /// Empty lifetime is for data that is never accessed. + /// Bottom in the region lattice. We treat ReEmpty somewhat + /// specially; at least right now, we do not generate instances of + /// it during the GLB computations, but rather + /// generate an error instead. This is to improve error messages. + /// The only way to get an instance of ReEmpty is to have a region + /// variable with no constraints. + ReEmpty, +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)] +pub struct EarlyBoundRegion { + pub space: subst::ParamSpace, + pub index: u32, + pub name: Name, +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct TyVid { + pub index: u32 +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct IntVid { + pub index: u32 +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct FloatVid { + pub index: u32 +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)] +pub struct RegionVid { + pub index: u32 +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub struct SkolemizedRegionVid { + pub index: u32 +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub enum InferTy { + TyVar(TyVid), + IntVar(IntVid), + FloatVar(FloatVid), + + /// A `FreshTy` is one that is generated as a replacement for an + /// unbound type variable. This is convenient for caching etc. See + /// `infer::freshen` for more details. + FreshTy(u32), + FreshIntTy(u32), + FreshFloatTy(u32) +} + +/// Bounds suitable for an existentially quantified type parameter +/// such as those that appear in object types or closure types. +#[derive(PartialEq, Eq, Hash, Clone)] +pub struct ExistentialBounds<'tcx> { + pub region_bound: ty::Region, + pub builtin_bounds: BuiltinBounds, + pub projection_bounds: Vec>, +} + +impl<'tcx> ExistentialBounds<'tcx> { + pub fn new(region_bound: ty::Region, + builtin_bounds: BuiltinBounds, + projection_bounds: Vec>) + -> Self { + let mut projection_bounds = projection_bounds; + projection_bounds.sort_by(|a, b| a.sort_key().cmp(&b.sort_key())); + ExistentialBounds { + region_bound: region_bound, + builtin_bounds: builtin_bounds, + projection_bounds: projection_bounds + } + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub struct BuiltinBounds(EnumSet); + +impl BuiltinBounds { + pub fn empty() -> BuiltinBounds { + BuiltinBounds(EnumSet::new()) + } + + pub fn iter(&self) -> enum_set::Iter { + self.into_iter() + } + + pub fn to_predicates<'tcx>(&self, + tcx: &TyCtxt<'tcx>, + self_ty: Ty<'tcx>) -> Vec> { + self.iter().filter_map(|builtin_bound| + match traits::trait_ref_for_builtin_bound(tcx, builtin_bound, self_ty) { + Ok(trait_ref) => Some(trait_ref.to_predicate()), + Err(ErrorReported) => { None } + } + ).collect() + } +} + +impl ops::Deref for BuiltinBounds { + type Target = EnumSet; + fn deref(&self) -> &Self::Target { &self.0 } +} + +impl ops::DerefMut for BuiltinBounds { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } +} + +impl<'a> IntoIterator for &'a BuiltinBounds { + type Item = BuiltinBound; + type IntoIter = enum_set::Iter; + fn into_iter(self) -> Self::IntoIter { + (**self).into_iter() + } +} + +#[derive(Clone, RustcEncodable, PartialEq, Eq, RustcDecodable, Hash, + Debug, Copy)] +#[repr(usize)] +pub enum BuiltinBound { + Send, + Sized, + Copy, + Sync, +} + +impl CLike for BuiltinBound { + fn to_usize(&self) -> usize { + *self as usize + } + fn from_usize(v: usize) -> BuiltinBound { + unsafe { mem::transmute(v) } + } +} + +impl<'tcx> TyCtxt<'tcx> { + pub fn try_add_builtin_trait(&self, + trait_def_id: DefId, + builtin_bounds: &mut EnumSet) + -> bool + { + //! Checks whether `trait_ref` refers to one of the builtin + //! traits, like `Send`, and adds the corresponding + //! bound to the set `builtin_bounds` if so. Returns true if `trait_ref` + //! is a builtin trait. + + match self.lang_items.to_builtin_kind(trait_def_id) { + Some(bound) => { builtin_bounds.insert(bound); true } + None => false + } + } +} + +impl DebruijnIndex { + pub fn new(depth: u32) -> DebruijnIndex { + assert!(depth > 0); + DebruijnIndex { depth: depth } + } + + pub fn shifted(&self, amount: u32) -> DebruijnIndex { + DebruijnIndex { depth: self.depth + amount } + } +} + +// Region utilities +impl Region { + pub fn is_bound(&self) -> bool { + match *self { + ty::ReEarlyBound(..) => true, + ty::ReLateBound(..) => true, + _ => false + } + } + + pub fn needs_infer(&self) -> bool { + match *self { + ty::ReVar(..) | ty::ReSkolemized(..) => true, + _ => false + } + } + + pub fn escapes_depth(&self, depth: u32) -> bool { + match *self { + ty::ReLateBound(debruijn, _) => debruijn.depth > depth, + _ => false, + } + } + + /// Returns the depth of `self` from the (1-based) binding level `depth` + pub fn from_depth(&self, depth: u32) -> Region { + match *self { + ty::ReLateBound(debruijn, r) => ty::ReLateBound(DebruijnIndex { + depth: debruijn.depth - (depth - 1) + }, r), + r => r + } + } +} + +// Type utilities +impl<'tcx> TyS<'tcx> { + pub fn as_opt_param_ty(&self) -> Option { + match self.sty { + ty::TyParam(ref d) => Some(d.clone()), + _ => None, + } + } + + pub fn is_nil(&self) -> bool { + match self.sty { + TyTuple(ref tys) => tys.is_empty(), + _ => false + } + } + + pub fn is_empty(&self, _cx: &TyCtxt) -> bool { + // FIXME(#24885): be smarter here + match self.sty { + TyEnum(def, _) | TyStruct(def, _) => def.is_empty(), + _ => false + } + } + + pub fn is_primitive(&self) -> bool { + match self.sty { + TyBool | TyChar | TyInt(_) | TyUint(_) | TyFloat(_) => true, + _ => false, + } + } + + pub fn is_ty_var(&self) -> bool { + match self.sty { + TyInfer(TyVar(_)) => true, + _ => false + } + } + + pub fn is_phantom_data(&self) -> bool { + if let TyStruct(def, _) = self.sty { + def.is_phantom_data() + } else { + false + } + } + + pub fn is_bool(&self) -> bool { self.sty == TyBool } + + pub fn is_param(&self, space: subst::ParamSpace, index: u32) -> bool { + match self.sty { + ty::TyParam(ref data) => data.space == space && data.idx == index, + _ => false, + } + } + + pub fn is_self(&self) -> bool { + match self.sty { + TyParam(ref p) => p.space == subst::SelfSpace, + _ => false + } + } + + pub fn is_slice(&self) -> bool { + match self.sty { + TyRawPtr(mt) | TyRef(_, mt) => match mt.ty.sty { + TySlice(_) | TyStr => true, + _ => false, + }, + _ => false + } + } + + pub fn is_structural(&self) -> bool { + match self.sty { + TyStruct(..) | TyTuple(_) | TyEnum(..) | + TyArray(..) | TyClosure(..) => true, + _ => self.is_slice() | self.is_trait() + } + } + + #[inline] + pub fn is_simd(&self) -> bool { + match self.sty { + TyStruct(def, _) => def.is_simd(), + _ => false + } + } + + pub fn sequence_element_type(&self, cx: &TyCtxt<'tcx>) -> Ty<'tcx> { + match self.sty { + TyArray(ty, _) | TySlice(ty) => ty, + TyStr => cx.mk_mach_uint(ast::UintTy::U8), + _ => cx.sess.bug(&format!("sequence_element_type called on non-sequence value: {}", + self)), + } + } + + pub fn simd_type(&self, cx: &TyCtxt<'tcx>) -> Ty<'tcx> { + match self.sty { + TyStruct(def, substs) => { + def.struct_variant().fields[0].ty(cx, substs) + } + _ => panic!("simd_type called on invalid type") + } + } + + pub fn simd_size(&self, _cx: &TyCtxt) -> usize { + match self.sty { + TyStruct(def, _) => def.struct_variant().fields.len(), + _ => panic!("simd_size called on invalid type") + } + } + + pub fn is_region_ptr(&self) -> bool { + match self.sty { + TyRef(..) => true, + _ => false + } + } + + pub fn is_unsafe_ptr(&self) -> bool { + match self.sty { + TyRawPtr(_) => return true, + _ => return false + } + } + + pub fn is_unique(&self) -> bool { + match self.sty { + TyBox(_) => true, + _ => false + } + } + + /* + A scalar type is one that denotes an atomic datum, with no sub-components. + (A TyRawPtr is scalar because it represents a non-managed pointer, so its + contents are abstract to rustc.) + */ + pub fn is_scalar(&self) -> bool { + match self.sty { + TyBool | TyChar | TyInt(_) | TyFloat(_) | TyUint(_) | + TyInfer(IntVar(_)) | TyInfer(FloatVar(_)) | + TyFnDef(..) | TyFnPtr(_) | TyRawPtr(_) => true, + _ => false + } + } + + /// Returns true if this type is a floating point type and false otherwise. + pub fn is_floating_point(&self) -> bool { + match self.sty { + TyFloat(_) | + TyInfer(FloatVar(_)) => true, + _ => false, + } + } + + pub fn is_trait(&self) -> bool { + match self.sty { + TyTrait(..) => true, + _ => false + } + } + + pub fn is_integral(&self) -> bool { + match self.sty { + TyInfer(IntVar(_)) | TyInt(_) | TyUint(_) => true, + _ => false + } + } + + pub fn is_fresh(&self) -> bool { + match self.sty { + TyInfer(FreshTy(_)) => true, + TyInfer(FreshIntTy(_)) => true, + TyInfer(FreshFloatTy(_)) => true, + _ => false + } + } + + pub fn is_uint(&self) -> bool { + match self.sty { + TyInfer(IntVar(_)) | TyUint(ast::UintTy::Us) => true, + _ => false + } + } + + pub fn is_char(&self) -> bool { + match self.sty { + TyChar => true, + _ => false + } + } + + pub fn is_fp(&self) -> bool { + match self.sty { + TyInfer(FloatVar(_)) | TyFloat(_) => true, + _ => false + } + } + + pub fn is_numeric(&self) -> bool { + self.is_integral() || self.is_fp() + } + + pub fn is_signed(&self) -> bool { + match self.sty { + TyInt(_) => true, + _ => false + } + } + + pub fn is_machine(&self) -> bool { + match self.sty { + TyInt(ast::IntTy::Is) | TyUint(ast::UintTy::Us) => false, + TyInt(..) | TyUint(..) | TyFloat(..) => true, + _ => false + } + } + + pub fn has_concrete_skeleton(&self) -> bool { + match self.sty { + TyParam(_) | TyInfer(_) | TyError => false, + _ => true, + } + } + + // Returns the type and mutability of *ty. + // + // The parameter `explicit` indicates if this is an *explicit* dereference. + // Some types---notably unsafe ptrs---can only be dereferenced explicitly. + pub fn builtin_deref(&self, explicit: bool, pref: ty::LvaluePreference) + -> Option> + { + match self.sty { + TyBox(ty) => { + Some(TypeAndMut { + ty: ty, + mutbl: if pref == ty::PreferMutLvalue { + hir::MutMutable + } else { + hir::MutImmutable + }, + }) + }, + TyRef(_, mt) => Some(mt), + TyRawPtr(mt) if explicit => Some(mt), + _ => None + } + } + + // Returns the type of ty[i] + pub fn builtin_index(&self) -> Option> { + match self.sty { + TyArray(ty, _) | TySlice(ty) => Some(ty), + _ => None + } + } + + pub fn fn_sig(&self) -> &'tcx PolyFnSig<'tcx> { + match self.sty { + TyFnDef(_, _, ref f) | TyFnPtr(ref f) => &f.sig, + _ => panic!("Ty::fn_sig() called on non-fn type: {:?}", self) + } + } + + /// Returns the ABI of the given function. + pub fn fn_abi(&self) -> abi::Abi { + match self.sty { + TyFnDef(_, _, ref f) | TyFnPtr(ref f) => f.abi, + _ => panic!("Ty::fn_abi() called on non-fn type"), + } + } + + // Type accessors for substructures of types + pub fn fn_args(&self) -> ty::Binder>> { + self.fn_sig().inputs() + } + + pub fn fn_ret(&self) -> Binder> { + self.fn_sig().output() + } + + pub fn is_fn(&self) -> bool { + match self.sty { + TyFnDef(..) | TyFnPtr(_) => true, + _ => false + } + } + + pub fn ty_to_def_id(&self) -> Option { + match self.sty { + TyTrait(ref tt) => Some(tt.principal_def_id()), + TyStruct(def, _) | + TyEnum(def, _) => Some(def.did), + TyClosure(id, _) => Some(id), + _ => None + } + } + + pub fn ty_adt_def(&self) -> Option> { + match self.sty { + TyStruct(adt, _) | TyEnum(adt, _) => Some(adt), + _ => None + } + } + + /// Returns the regions directly referenced from this type (but + /// not types reachable from this type via `walk_tys`). This + /// ignores late-bound regions binders. + pub fn regions(&self) -> Vec { + match self.sty { + TyRef(region, _) => { + vec![*region] + } + TyTrait(ref obj) => { + let mut v = vec![obj.bounds.region_bound]; + v.extend_from_slice(obj.principal.skip_binder() + .substs.regions.as_slice()); + v + } + TyEnum(_, substs) | + TyStruct(_, substs) => { + substs.regions.as_slice().to_vec() + } + TyClosure(_, ref substs) => { + substs.func_substs.regions.as_slice().to_vec() + } + TyProjection(ref data) => { + data.trait_ref.substs.regions.as_slice().to_vec() + } + TyFnDef(..) | + TyFnPtr(_) | + TyBool | + TyChar | + TyInt(_) | + TyUint(_) | + TyFloat(_) | + TyBox(_) | + TyStr | + TyArray(_, _) | + TySlice(_) | + TyRawPtr(_) | + TyTuple(_) | + TyParam(_) | + TyInfer(_) | + TyError => { + vec![] + } + } + } +} diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs new file mode 100644 index 00000000000..8d257282121 --- /dev/null +++ b/src/librustc/ty/subst.rs @@ -0,0 +1,737 @@ +// Copyright 2012 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Type substitutions. + +pub use self::ParamSpace::*; + +use middle::cstore; +use middle::def_id::DefId; +use ty::{self, Ty, TyCtxt}; +use ty::fold::{TypeFoldable, TypeFolder}; + +use serialize::{Encodable, Encoder, Decodable, Decoder}; +use std::fmt; +use std::iter::IntoIterator; +use std::slice::Iter; +use std::vec::{Vec, IntoIter}; +use syntax::codemap::{Span, DUMMY_SP}; + +/////////////////////////////////////////////////////////////////////////// + +/// A substitution mapping type/region parameters to new values. We +/// identify each in-scope parameter by an *index* and a *parameter +/// space* (which indices where the parameter is defined; see +/// `ParamSpace`). +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct Substs<'tcx> { + pub types: VecPerParamSpace>, + pub regions: VecPerParamSpace, +} + +impl<'tcx> Substs<'tcx> { + pub fn new(t: VecPerParamSpace>, + r: VecPerParamSpace) + -> Substs<'tcx> + { + Substs { types: t, regions: r } + } + + pub fn new_type(t: Vec>, + r: Vec) + -> Substs<'tcx> + { + Substs::new(VecPerParamSpace::new(t, Vec::new(), Vec::new()), + VecPerParamSpace::new(r, Vec::new(), Vec::new())) + } + + pub fn new_trait(t: Vec>, + r: Vec, + s: Ty<'tcx>) + -> Substs<'tcx> + { + Substs::new(VecPerParamSpace::new(t, vec!(s), Vec::new()), + VecPerParamSpace::new(r, Vec::new(), Vec::new())) + } + + pub fn empty() -> Substs<'tcx> { + Substs { + types: VecPerParamSpace::empty(), + regions: VecPerParamSpace::empty(), + } + } + + pub fn is_noop(&self) -> bool { + self.regions.is_empty() && self.types.is_empty() + } + + pub fn type_for_def(&self, ty_param_def: &ty::TypeParameterDef) -> Ty<'tcx> { + *self.types.get(ty_param_def.space, ty_param_def.index as usize) + } + + pub fn self_ty(&self) -> Option> { + self.types.get_self().cloned() + } + + pub fn with_self_ty(&self, self_ty: Ty<'tcx>) -> Substs<'tcx> { + assert!(self.self_ty().is_none()); + let mut s = (*self).clone(); + s.types.push(SelfSpace, self_ty); + s + } + + pub fn erase_regions(self) -> Substs<'tcx> { + let Substs { types, regions } = self; + let regions = regions.map(|_| ty::ReStatic); + Substs { types: types, regions: regions } + } + + pub fn with_method(self, + m_types: Vec>, + m_regions: Vec) + -> Substs<'tcx> + { + let Substs { types, regions } = self; + let types = types.with_slice(FnSpace, &m_types); + let regions = regions.with_slice(FnSpace, &m_regions); + Substs { types: types, regions: regions } + } + + pub fn with_method_from(&self, + meth_substs: &Substs<'tcx>) + -> Substs<'tcx> + { + let Substs { types, regions } = self.clone(); + let types = types.with_slice(FnSpace, meth_substs.types.get_slice(FnSpace)); + let regions = regions.with_slice(FnSpace, meth_substs.regions.get_slice(FnSpace)); + Substs { types: types, regions: regions } + } + + pub fn with_method_from_subst(self, other: &Substs<'tcx>) -> Substs<'tcx> { + let Substs { types, regions } = self; + let types = types.with_slice(FnSpace, other.types.get_slice(FnSpace)); + let regions = regions.with_slice(FnSpace, other.regions.get_slice(FnSpace)); + Substs { types: types, regions: regions } + } + + /// Creates a trait-ref out of this substs, ignoring the FnSpace substs + pub fn to_trait_ref(&self, tcx: &TyCtxt<'tcx>, trait_id: DefId) + -> ty::TraitRef<'tcx> { + let Substs { mut types, mut regions } = self.clone(); + types.truncate(FnSpace, 0); + regions.truncate(FnSpace, 0); + + ty::TraitRef { + def_id: trait_id, + substs: tcx.mk_substs(Substs { types: types, regions: regions }) + } + } +} + +impl<'tcx> Encodable for Substs<'tcx> { + + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + cstore::tls::with_encoding_context(s, |ecx, rbml_w| { + ecx.encode_substs(rbml_w, self); + Ok(()) + }) + } +} + +impl<'tcx> Decodable for Substs<'tcx> { + fn decode(d: &mut D) -> Result, D::Error> { + cstore::tls::with_decoding_context(d, |dcx, rbml_r| { + Ok(dcx.decode_substs(rbml_r)) + }) + } +} + +impl<'tcx> Decodable for &'tcx Substs<'tcx> { + fn decode(d: &mut D) -> Result<&'tcx Substs<'tcx>, D::Error> { + let substs = cstore::tls::with_decoding_context(d, |dcx, rbml_r| { + let substs = dcx.decode_substs(rbml_r); + dcx.tcx().mk_substs(substs) + }); + + Ok(substs) + } +} + +/////////////////////////////////////////////////////////////////////////// +// ParamSpace + +#[derive(PartialOrd, Ord, PartialEq, Eq, Copy, + Clone, Hash, RustcEncodable, RustcDecodable, Debug)] +pub enum ParamSpace { + TypeSpace, // Type parameters attached to a type definition, trait, or impl + SelfSpace, // Self parameter on a trait + FnSpace, // Type parameters attached to a method or fn +} + +impl ParamSpace { + pub fn all() -> [ParamSpace; 3] { + [TypeSpace, SelfSpace, FnSpace] + } + + pub fn to_uint(self) -> usize { + match self { + TypeSpace => 0, + SelfSpace => 1, + FnSpace => 2, + } + } + + pub fn from_uint(u: usize) -> ParamSpace { + match u { + 0 => TypeSpace, + 1 => SelfSpace, + 2 => FnSpace, + _ => panic!("Invalid ParamSpace: {}", u) + } + } +} + +/// Vector of things sorted by param space. Used to keep +/// the set of things declared on the type, self, or method +/// distinct. +#[derive(PartialEq, Eq, Clone, Hash, RustcEncodable, RustcDecodable)] +pub struct VecPerParamSpace { + // This was originally represented as a tuple with one Vec for + // each variant of ParamSpace, and that remains the abstraction + // that it provides to its clients. + // + // Here is how the representation corresponds to the abstraction + // i.e. the "abstraction function" AF: + // + // AF(self) = (self.content[..self.type_limit], + // self.content[self.type_limit..self.self_limit], + // self.content[self.self_limit..]) + type_limit: usize, + self_limit: usize, + content: Vec, +} + +/// The `split` function converts one `VecPerParamSpace` into this +/// `SeparateVecsPerParamSpace` structure. +pub struct SeparateVecsPerParamSpace { + pub types: Vec, + pub selfs: Vec, + pub fns: Vec, +} + +impl fmt::Debug for VecPerParamSpace { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "[{:?};{:?};{:?}]", + self.get_slice(TypeSpace), + self.get_slice(SelfSpace), + self.get_slice(FnSpace)) + } +} + +impl VecPerParamSpace { + fn limits(&self, space: ParamSpace) -> (usize, usize) { + match space { + TypeSpace => (0, self.type_limit), + SelfSpace => (self.type_limit, self.self_limit), + FnSpace => (self.self_limit, self.content.len()), + } + } + + pub fn empty() -> VecPerParamSpace { + VecPerParamSpace { + type_limit: 0, + self_limit: 0, + content: Vec::new() + } + } + + /// `t` is the type space. + /// `s` is the self space. + /// `f` is the fn space. + pub fn new(t: Vec, s: Vec, f: Vec) -> VecPerParamSpace { + let type_limit = t.len(); + let self_limit = type_limit + s.len(); + + let mut content = t; + content.extend(s); + content.extend(f); + + VecPerParamSpace { + type_limit: type_limit, + self_limit: self_limit, + content: content, + } + } + + fn new_internal(content: Vec, type_limit: usize, self_limit: usize) + -> VecPerParamSpace + { + VecPerParamSpace { + type_limit: type_limit, + self_limit: self_limit, + content: content, + } + } + + /// Appends `value` to the vector associated with `space`. + /// + /// Unlike the `push` method in `Vec`, this should not be assumed + /// to be a cheap operation (even when amortized over many calls). + pub fn push(&mut self, space: ParamSpace, value: T) { + let (_, limit) = self.limits(space); + match space { + TypeSpace => { self.type_limit += 1; self.self_limit += 1; } + SelfSpace => { self.self_limit += 1; } + FnSpace => { } + } + self.content.insert(limit, value); + } + + /// Appends `values` to the vector associated with `space`. + /// + /// Unlike the `extend` method in `Vec`, this should not be assumed + /// to be a cheap operation (even when amortized over many calls). + pub fn extend>(&mut self, space: ParamSpace, values: I) { + // This could be made more efficient, obviously. + for item in values { + self.push(space, item); + } + } + + pub fn pop(&mut self, space: ParamSpace) -> Option { + let (start, limit) = self.limits(space); + if start == limit { + None + } else { + match space { + TypeSpace => { self.type_limit -= 1; self.self_limit -= 1; } + SelfSpace => { self.self_limit -= 1; } + FnSpace => {} + } + if self.content.is_empty() { + None + } else { + Some(self.content.remove(limit - 1)) + } + } + } + + pub fn truncate(&mut self, space: ParamSpace, len: usize) { + // FIXME (#15435): slow; O(n^2); could enhance vec to make it O(n). + while self.len(space) > len { + self.pop(space); + } + } + + pub fn replace(&mut self, space: ParamSpace, elems: Vec) { + // FIXME (#15435): slow; O(n^2); could enhance vec to make it O(n). + self.truncate(space, 0); + for t in elems { + self.push(space, t); + } + } + + pub fn get_self<'a>(&'a self) -> Option<&'a T> { + let v = self.get_slice(SelfSpace); + assert!(v.len() <= 1); + if v.is_empty() { None } else { Some(&v[0]) } + } + + pub fn len(&self, space: ParamSpace) -> usize { + self.get_slice(space).len() + } + + pub fn is_empty_in(&self, space: ParamSpace) -> bool { + self.len(space) == 0 + } + + pub fn get_slice<'a>(&'a self, space: ParamSpace) -> &'a [T] { + let (start, limit) = self.limits(space); + &self.content[start.. limit] + } + + pub fn get_mut_slice<'a>(&'a mut self, space: ParamSpace) -> &'a mut [T] { + let (start, limit) = self.limits(space); + &mut self.content[start.. limit] + } + + pub fn opt_get<'a>(&'a self, + space: ParamSpace, + index: usize) + -> Option<&'a T> { + let v = self.get_slice(space); + if index < v.len() { Some(&v[index]) } else { None } + } + + pub fn get<'a>(&'a self, space: ParamSpace, index: usize) -> &'a T { + &self.get_slice(space)[index] + } + + pub fn iter<'a>(&'a self) -> Iter<'a,T> { + self.content.iter() + } + + pub fn into_iter(self) -> IntoIter { + self.content.into_iter() + } + + pub fn iter_enumerated<'a>(&'a self) -> EnumeratedItems<'a,T> { + EnumeratedItems::new(self) + } + + pub fn as_slice(&self) -> &[T] { + &self.content + } + + pub fn into_vec(self) -> Vec { + self.content + } + + pub fn all_vecs

(&self, mut pred: P) -> bool where + P: FnMut(&[T]) -> bool, + { + let spaces = [TypeSpace, SelfSpace, FnSpace]; + spaces.iter().all(|&space| { pred(self.get_slice(space)) }) + } + + pub fn all

(&self, pred: P) -> bool where P: FnMut(&T) -> bool { + self.iter().all(pred) + } + + pub fn any

(&self, pred: P) -> bool where P: FnMut(&T) -> bool { + self.iter().any(pred) + } + + pub fn is_empty(&self) -> bool { + self.all_vecs(|v| v.is_empty()) + } + + pub fn map(&self, pred: P) -> VecPerParamSpace where P: FnMut(&T) -> U { + let result = self.iter().map(pred).collect(); + VecPerParamSpace::new_internal(result, + self.type_limit, + self.self_limit) + } + + pub fn map_enumerated(&self, pred: P) -> VecPerParamSpace where + P: FnMut((ParamSpace, usize, &T)) -> U, + { + let result = self.iter_enumerated().map(pred).collect(); + VecPerParamSpace::new_internal(result, + self.type_limit, + self.self_limit) + } + + pub fn split(self) -> SeparateVecsPerParamSpace { + let VecPerParamSpace { type_limit, self_limit, content } = self; + + let mut content_iter = content.into_iter(); + + SeparateVecsPerParamSpace { + types: content_iter.by_ref().take(type_limit).collect(), + selfs: content_iter.by_ref().take(self_limit - type_limit).collect(), + fns: content_iter.collect() + } + } + + pub fn with_slice(mut self, space: ParamSpace, slice: &[T]) + -> VecPerParamSpace + where T: Clone + { + assert!(self.is_empty_in(space)); + for t in slice { + self.push(space, t.clone()); + } + + self + } +} + +#[derive(Clone)] +pub struct EnumeratedItems<'a,T:'a> { + vec: &'a VecPerParamSpace, + space_index: usize, + elem_index: usize +} + +impl<'a,T> EnumeratedItems<'a,T> { + fn new(v: &'a VecPerParamSpace) -> EnumeratedItems<'a,T> { + let mut result = EnumeratedItems { vec: v, space_index: 0, elem_index: 0 }; + result.adjust_space(); + result + } + + fn adjust_space(&mut self) { + let spaces = ParamSpace::all(); + while + self.space_index < spaces.len() && + self.elem_index >= self.vec.len(spaces[self.space_index]) + { + self.space_index += 1; + self.elem_index = 0; + } + } +} + +impl<'a,T> Iterator for EnumeratedItems<'a,T> { + type Item = (ParamSpace, usize, &'a T); + + fn next(&mut self) -> Option<(ParamSpace, usize, &'a T)> { + let spaces = ParamSpace::all(); + if self.space_index < spaces.len() { + let space = spaces[self.space_index]; + let index = self.elem_index; + let item = self.vec.get(space, index); + + self.elem_index += 1; + self.adjust_space(); + + Some((space, index, item)) + } else { + None + } + } + + fn size_hint(&self) -> (usize, Option) { + let size = self.vec.as_slice().len(); + (size, Some(size)) + } +} + +impl IntoIterator for VecPerParamSpace { + type Item = T; + type IntoIter = IntoIter; + + fn into_iter(self) -> IntoIter { + self.into_vec().into_iter() + } +} + +impl<'a,T> IntoIterator for &'a VecPerParamSpace { + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.as_slice().into_iter() + } +} + + +/////////////////////////////////////////////////////////////////////////// +// Public trait `Subst` +// +// Just call `foo.subst(tcx, substs)` to perform a substitution across +// `foo`. Or use `foo.subst_spanned(tcx, substs, Some(span))` when +// there is more information available (for better errors). + +pub trait Subst<'tcx> : Sized { + fn subst(&self, tcx: &TyCtxt<'tcx>, substs: &Substs<'tcx>) -> Self { + self.subst_spanned(tcx, substs, None) + } + + fn subst_spanned(&self, tcx: &TyCtxt<'tcx>, + substs: &Substs<'tcx>, + span: Option) + -> Self; +} + +impl<'tcx, T:TypeFoldable<'tcx>> Subst<'tcx> for T { + fn subst_spanned(&self, + tcx: &TyCtxt<'tcx>, + substs: &Substs<'tcx>, + span: Option) + -> T + { + let mut folder = SubstFolder { tcx: tcx, + substs: substs, + span: span, + root_ty: None, + ty_stack_depth: 0, + region_binders_passed: 0 }; + (*self).fold_with(&mut folder) + } +} + +/////////////////////////////////////////////////////////////////////////// +// The actual substitution engine itself is a type folder. + +struct SubstFolder<'a, 'tcx: 'a> { + tcx: &'a TyCtxt<'tcx>, + substs: &'a Substs<'tcx>, + + // The location for which the substitution is performed, if available. + span: Option, + + // The root type that is being substituted, if available. + root_ty: Option>, + + // Depth of type stack + ty_stack_depth: usize, + + // Number of region binders we have passed through while doing the substitution + region_binders_passed: u32, +} + +impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { + fn tcx(&self) -> &TyCtxt<'tcx> { self.tcx } + + fn enter_region_binder(&mut self) { + self.region_binders_passed += 1; + } + + fn exit_region_binder(&mut self) { + self.region_binders_passed -= 1; + } + + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + // Note: This routine only handles regions that are bound on + // type declarations and other outer declarations, not those + // bound in *fn types*. Region substitution of the bound + // regions that appear in a function signature is done using + // the specialized routine `ty::replace_late_regions()`. + match r { + ty::ReEarlyBound(data) => { + match self.substs.regions.opt_get(data.space, data.index as usize) { + Some(&r) => { + self.shift_region_through_binders(r) + } + None => { + let span = self.span.unwrap_or(DUMMY_SP); + self.tcx().sess.span_bug( + span, + &format!("Region parameter out of range \ + when substituting in region {} (root type={:?}) \ + (space={:?}, index={})", + data.name, + self.root_ty, + data.space, + data.index)); + } + } + } + _ => r + } + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + if !t.needs_subst() { + return t; + } + + // track the root type we were asked to substitute + let depth = self.ty_stack_depth; + if depth == 0 { + self.root_ty = Some(t); + } + self.ty_stack_depth += 1; + + let t1 = match t.sty { + ty::TyParam(p) => { + self.ty_for_param(p, t) + } + _ => { + t.super_fold_with(self) + } + }; + + assert_eq!(depth + 1, self.ty_stack_depth); + self.ty_stack_depth -= 1; + if depth == 0 { + self.root_ty = None; + } + + return t1; + } +} + +impl<'a,'tcx> SubstFolder<'a,'tcx> { + fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> { + // Look up the type in the substitutions. It really should be in there. + let opt_ty = self.substs.types.opt_get(p.space, p.idx as usize); + let ty = match opt_ty { + Some(t) => *t, + None => { + let span = self.span.unwrap_or(DUMMY_SP); + self.tcx().sess.span_bug( + span, + &format!("Type parameter `{:?}` ({:?}/{:?}/{}) out of range \ + when substituting (root type={:?}) substs={:?}", + p, + source_ty, + p.space, + p.idx, + self.root_ty, + self.substs)); + } + }; + + self.shift_regions_through_binders(ty) + } + + /// It is sometimes necessary to adjust the debruijn indices during substitution. This occurs + /// when we are substituting a type with escaping regions into a context where we have passed + /// through region binders. That's quite a mouthful. Let's see an example: + /// + /// ``` + /// type Func = fn(A); + /// type MetaFunc = for<'a> fn(Func<&'a int>) + /// ``` + /// + /// The type `MetaFunc`, when fully expanded, will be + /// + /// for<'a> fn(fn(&'a int)) + /// ^~ ^~ ^~~ + /// | | | + /// | | DebruijnIndex of 2 + /// Binders + /// + /// Here the `'a` lifetime is bound in the outer function, but appears as an argument of the + /// inner one. Therefore, that appearance will have a DebruijnIndex of 2, because we must skip + /// over the inner binder (remember that we count Debruijn indices from 1). However, in the + /// definition of `MetaFunc`, the binder is not visible, so the type `&'a int` will have a + /// debruijn index of 1. It's only during the substitution that we can see we must increase the + /// depth by 1 to account for the binder that we passed through. + /// + /// As a second example, consider this twist: + /// + /// ``` + /// type FuncTuple = (A,fn(A)); + /// type MetaFuncTuple = for<'a> fn(FuncTuple<&'a int>) + /// ``` + /// + /// Here the final type will be: + /// + /// for<'a> fn((&'a int, fn(&'a int))) + /// ^~~ ^~~ + /// | | + /// DebruijnIndex of 1 | + /// DebruijnIndex of 2 + /// + /// As indicated in the diagram, here the same type `&'a int` is substituted once, but in the + /// first case we do not increase the Debruijn index and in the second case we do. The reason + /// is that only in the second case have we passed through a fn binder. + fn shift_regions_through_binders(&self, ty: Ty<'tcx>) -> Ty<'tcx> { + debug!("shift_regions(ty={:?}, region_binders_passed={:?}, has_escaping_regions={:?})", + ty, self.region_binders_passed, ty.has_escaping_regions()); + + if self.region_binders_passed == 0 || !ty.has_escaping_regions() { + return ty; + } + + let result = ty::fold::shift_regions(self.tcx(), self.region_binders_passed, &ty); + debug!("shift_regions: shifted result = {:?}", result); + + result + } + + fn shift_region_through_binders(&self, region: ty::Region) -> ty::Region { + ty::fold::shift_region(region, self.region_binders_passed) + } +} diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs new file mode 100644 index 00000000000..3ebf2ba4c84 --- /dev/null +++ b/src/librustc/ty/trait_def.rs @@ -0,0 +1,282 @@ +// Copyright 2012-2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use dep_graph::DepNode; +use middle::def_id::DefId; +use traits::{self, specialization_graph}; +use ty; +use ty::fast_reject; +use ty::{Ty, TyCtxt, TraitRef}; +use std::borrow::{Borrow}; +use std::cell::{Cell, Ref, RefCell}; +use syntax::ast::Name; +use rustc_front::hir; +use util::nodemap::FnvHashMap; + +/// As `TypeScheme` but for a trait ref. +pub struct TraitDef<'tcx> { + pub unsafety: hir::Unsafety, + + /// If `true`, then this trait had the `#[rustc_paren_sugar]` + /// attribute, indicating that it should be used with `Foo()` + /// sugar. This is a temporary thing -- eventually any trait wil + /// be usable with the sugar (or without it). + pub paren_sugar: bool, + + /// Generic type definitions. Note that `Self` is listed in here + /// as having a single bound, the trait itself (e.g., in the trait + /// `Eq`, there is a single bound `Self : Eq`). This is so that + /// default methods get to assume that the `Self` parameters + /// implements the trait. + pub generics: ty::Generics<'tcx>, + + pub trait_ref: ty::TraitRef<'tcx>, + + /// A list of the associated types defined in this trait. Useful + /// for resolving `X::Foo` type markers. + pub associated_type_names: Vec, + + // Impls of this trait. To allow for quicker lookup, the impls are indexed + // by a simplified version of their Self type: impls with a simplifiable + // Self are stored in nonblanket_impls keyed by it, while all other impls + // are stored in blanket_impls. + // + // These lists are tracked by `DepNode::TraitImpls`; we don't use + // a DepTrackingMap but instead have the `TraitDef` insert the + // required reads/writes. + + /// Impls of the trait. + nonblanket_impls: RefCell< + FnvHashMap> + >, + + /// Blanket impls associated with the trait. + blanket_impls: RefCell>, + + /// The specialization order for impls of this trait. + pub specialization_graph: RefCell, + + /// Various flags + pub flags: Cell +} + +impl<'tcx> TraitDef<'tcx> { + pub fn new(unsafety: hir::Unsafety, + paren_sugar: bool, + generics: ty::Generics<'tcx>, + trait_ref: ty::TraitRef<'tcx>, + associated_type_names: Vec) + -> TraitDef<'tcx> { + TraitDef { + paren_sugar: paren_sugar, + unsafety: unsafety, + generics: generics, + trait_ref: trait_ref, + associated_type_names: associated_type_names, + nonblanket_impls: RefCell::new(FnvHashMap()), + blanket_impls: RefCell::new(vec![]), + flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS), + specialization_graph: RefCell::new(traits::specialization_graph::Graph::new()), + } + } + + pub fn def_id(&self) -> DefId { + self.trait_ref.def_id + } + + // returns None if not yet calculated + pub fn object_safety(&self) -> Option { + if self.flags.get().intersects(TraitFlags::OBJECT_SAFETY_VALID) { + Some(self.flags.get().intersects(TraitFlags::IS_OBJECT_SAFE)) + } else { + None + } + } + + pub fn set_object_safety(&self, is_safe: bool) { + assert!(self.object_safety().map(|cs| cs == is_safe).unwrap_or(true)); + self.flags.set( + self.flags.get() | if is_safe { + TraitFlags::OBJECT_SAFETY_VALID | TraitFlags::IS_OBJECT_SAFE + } else { + TraitFlags::OBJECT_SAFETY_VALID + } + ); + } + + fn write_trait_impls(&self, tcx: &TyCtxt<'tcx>) { + tcx.dep_graph.write(DepNode::TraitImpls(self.trait_ref.def_id)); + } + + fn read_trait_impls(&self, tcx: &TyCtxt<'tcx>) { + tcx.dep_graph.read(DepNode::TraitImpls(self.trait_ref.def_id)); + } + + /// Records a basic trait-to-implementation mapping. + /// + /// Returns `true` iff the impl has not previously been recorded. + fn record_impl(&self, + tcx: &TyCtxt<'tcx>, + impl_def_id: DefId, + impl_trait_ref: TraitRef<'tcx>) + -> bool { + debug!("TraitDef::record_impl for {:?}, from {:?}", + self, impl_trait_ref); + + // Record the write into the impl set, but only for local + // impls: external impls are handled differently. + if impl_def_id.is_local() { + self.write_trait_impls(tcx); + } + + // We don't want to borrow_mut after we already populated all impls, + // so check if an impl is present with an immutable borrow first. + if let Some(sty) = fast_reject::simplify_type(tcx, + impl_trait_ref.self_ty(), false) { + if let Some(is) = self.nonblanket_impls.borrow().get(&sty) { + if is.contains(&impl_def_id) { + return false; // duplicate - skip + } + } + + self.nonblanket_impls.borrow_mut().entry(sty).or_insert(vec![]).push(impl_def_id) + } else { + if self.blanket_impls.borrow().contains(&impl_def_id) { + return false; // duplicate - skip + } + self.blanket_impls.borrow_mut().push(impl_def_id) + } + + true + } + + /// Records a trait-to-implementation mapping for a crate-local impl. + pub fn record_local_impl(&self, + tcx: &TyCtxt<'tcx>, + impl_def_id: DefId, + impl_trait_ref: TraitRef<'tcx>) { + assert!(impl_def_id.is_local()); + let was_new = self.record_impl(tcx, impl_def_id, impl_trait_ref); + assert!(was_new); + } + + /// Records a trait-to-implementation mapping for a non-local impl. + /// + /// The `parent_impl` is the immediately-less-specialized impl, or the + /// trait's def ID if the impl is is not a specialization -- information that + /// should be pulled from the metadata. + pub fn record_remote_impl(&self, + tcx: &TyCtxt<'tcx>, + impl_def_id: DefId, + impl_trait_ref: TraitRef<'tcx>, + parent_impl: DefId) { + assert!(!impl_def_id.is_local()); + + // if the impl has not previously been recorded + if self.record_impl(tcx, impl_def_id, impl_trait_ref) { + // if the impl is non-local, it's placed directly into the + // specialization graph using parent information drawn from metadata. + self.specialization_graph.borrow_mut() + .record_impl_from_cstore(parent_impl, impl_def_id) + } + } + + /// Adds a local impl into the specialization graph, returning an error with + /// overlap information if the impl overlaps but does not specialize an + /// existing impl. + pub fn add_impl_for_specialization<'a>(&self, + tcx: &'a TyCtxt<'tcx>, + impl_def_id: DefId) + -> Result<(), traits::Overlap<'a, 'tcx>> { + assert!(impl_def_id.is_local()); + + self.specialization_graph.borrow_mut() + .insert(tcx, impl_def_id) + } + + pub fn ancestors<'a>(&'a self, of_impl: DefId) -> specialization_graph::Ancestors<'a, 'tcx> { + specialization_graph::ancestors(self, of_impl) + } + + pub fn for_each_impl(&self, tcx: &TyCtxt<'tcx>, mut f: F) { + self.read_trait_impls(tcx); + tcx.populate_implementations_for_trait_if_necessary(self.trait_ref.def_id); + + for &impl_def_id in self.blanket_impls.borrow().iter() { + f(impl_def_id); + } + + for v in self.nonblanket_impls.borrow().values() { + for &impl_def_id in v { + f(impl_def_id); + } + } + } + + /// Iterate over every impl that could possibly match the + /// self-type `self_ty`. + pub fn for_each_relevant_impl(&self, + tcx: &TyCtxt<'tcx>, + self_ty: Ty<'tcx>, + mut f: F) + { + self.read_trait_impls(tcx); + + tcx.populate_implementations_for_trait_if_necessary(self.trait_ref.def_id); + + for &impl_def_id in self.blanket_impls.borrow().iter() { + f(impl_def_id); + } + + // simplify_type(.., false) basically replaces type parameters and + // projections with infer-variables. This is, of course, done on + // the impl trait-ref when it is instantiated, but not on the + // predicate trait-ref which is passed here. + // + // for example, if we match `S: Copy` against an impl like + // `impl Copy for Option`, we replace the type variable + // in `Option` with an infer variable, to `Option<_>` (this + // doesn't actually change fast_reject output), but we don't + // replace `S` with anything - this impl of course can't be + // selected, and as there are hundreds of similar impls, + // considering them would significantly harm performance. + if let Some(simp) = fast_reject::simplify_type(tcx, self_ty, true) { + if let Some(impls) = self.nonblanket_impls.borrow().get(&simp) { + for &impl_def_id in impls { + f(impl_def_id); + } + } + } else { + for v in self.nonblanket_impls.borrow().values() { + for &impl_def_id in v { + f(impl_def_id); + } + } + } + } + + pub fn borrow_impl_lists<'s>(&'s self, tcx: &TyCtxt<'tcx>) + -> (Ref<'s, Vec>, + Ref<'s, FnvHashMap>>) { + self.read_trait_impls(tcx); + (self.blanket_impls.borrow(), self.nonblanket_impls.borrow()) + } + +} + +bitflags! { + flags TraitFlags: u32 { + const NO_TRAIT_FLAGS = 0, + const HAS_DEFAULT_IMPL = 1 << 0, + const IS_OBJECT_SAFE = 1 << 1, + const OBJECT_SAFETY_VALID = 1 << 2, + const IMPLS_VALID = 1 << 3, + } +} diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs new file mode 100644 index 00000000000..b870dc47ec7 --- /dev/null +++ b/src/librustc/ty/util.rs @@ -0,0 +1,786 @@ +// Copyright 2012-2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! misc. type-system utilities too small to deserve their own file + +use back::svh::Svh; +use middle::const_eval::{self, ConstVal, ErrKind}; +use middle::const_eval::EvalHint::UncheckedExprHint; +use middle::def_id::DefId; +use ty::subst; +use infer; +use middle::pat_util; +use traits::{self, ProjectionMode}; +use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable}; +use ty::{Disr, ParameterEnvironment}; +use ty::TypeVariants::*; + +use rustc_const_eval::{ConstInt, ConstIsize, ConstUsize}; + +use std::cmp; +use std::hash::{Hash, SipHasher, Hasher}; +use syntax::ast::{self, Name}; +use syntax::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt}; +use syntax::codemap::Span; + +use rustc_front::hir; + +pub trait IntTypeExt { + fn to_ty<'tcx>(&self, cx: &TyCtxt<'tcx>) -> Ty<'tcx>; + fn disr_incr(&self, val: Disr) -> Option; + fn assert_ty_matches(&self, val: Disr); + fn initial_discriminant(&self, tcx: &TyCtxt) -> Disr; +} + +impl IntTypeExt for attr::IntType { + fn to_ty<'tcx>(&self, cx: &TyCtxt<'tcx>) -> Ty<'tcx> { + match *self { + SignedInt(ast::IntTy::I8) => cx.types.i8, + SignedInt(ast::IntTy::I16) => cx.types.i16, + SignedInt(ast::IntTy::I32) => cx.types.i32, + SignedInt(ast::IntTy::I64) => cx.types.i64, + SignedInt(ast::IntTy::Is) => cx.types.isize, + UnsignedInt(ast::UintTy::U8) => cx.types.u8, + UnsignedInt(ast::UintTy::U16) => cx.types.u16, + UnsignedInt(ast::UintTy::U32) => cx.types.u32, + UnsignedInt(ast::UintTy::U64) => cx.types.u64, + UnsignedInt(ast::UintTy::Us) => cx.types.usize, + } + } + + fn initial_discriminant(&self, tcx: &TyCtxt) -> Disr { + match *self { + SignedInt(ast::IntTy::I8) => ConstInt::I8(0), + SignedInt(ast::IntTy::I16) => ConstInt::I16(0), + SignedInt(ast::IntTy::I32) => ConstInt::I32(0), + SignedInt(ast::IntTy::I64) => ConstInt::I64(0), + SignedInt(ast::IntTy::Is) => match tcx.sess.target.int_type { + ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32(0)), + ast::IntTy::I64 => ConstInt::Isize(ConstIsize::Is64(0)), + _ => unreachable!(), + }, + UnsignedInt(ast::UintTy::U8) => ConstInt::U8(0), + UnsignedInt(ast::UintTy::U16) => ConstInt::U16(0), + UnsignedInt(ast::UintTy::U32) => ConstInt::U32(0), + UnsignedInt(ast::UintTy::U64) => ConstInt::U64(0), + UnsignedInt(ast::UintTy::Us) => match tcx.sess.target.uint_type { + ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32(0)), + ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64(0)), + _ => unreachable!(), + }, + } + } + + fn assert_ty_matches(&self, val: Disr) { + match (*self, val) { + (SignedInt(ast::IntTy::I8), ConstInt::I8(_)) => {}, + (SignedInt(ast::IntTy::I16), ConstInt::I16(_)) => {}, + (SignedInt(ast::IntTy::I32), ConstInt::I32(_)) => {}, + (SignedInt(ast::IntTy::I64), ConstInt::I64(_)) => {}, + (SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) => {}, + (UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) => {}, + (UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) => {}, + (UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) => {}, + (UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) => {}, + (UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => {}, + _ => panic!("disr type mismatch: {:?} vs {:?}", self, val), + } + } + + fn disr_incr(&self, val: Disr) -> Option { + self.assert_ty_matches(val); + (val + ConstInt::Infer(1)).ok() + } +} + + +#[derive(Copy, Clone)] +pub enum CopyImplementationError { + InfrigingField(Name), + InfrigingVariant(Name), + NotAnAdt, + HasDestructor +} + +/// Describes whether a type is representable. For types that are not +/// representable, 'SelfRecursive' and 'ContainsRecursive' are used to +/// distinguish between types that are recursive with themselves and types that +/// contain a different recursive type. These cases can therefore be treated +/// differently when reporting errors. +/// +/// The ordering of the cases is significant. They are sorted so that cmp::max +/// will keep the "more erroneous" of two values. +#[derive(Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Debug)] +pub enum Representability { + Representable, + ContainsRecursive, + SelfRecursive, +} + +impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { + pub fn can_type_implement_copy(&self, self_type: Ty<'tcx>, span: Span) + -> Result<(),CopyImplementationError> { + let tcx = self.tcx; + + // FIXME: (@jroesch) float this code up + let infcx = infer::new_infer_ctxt(tcx, + &tcx.tables, + Some(self.clone()), + ProjectionMode::Topmost); + + let adt = match self_type.sty { + ty::TyStruct(struct_def, substs) => { + for field in struct_def.all_fields() { + let field_ty = field.ty(tcx, substs); + if infcx.type_moves_by_default(field_ty, span) { + return Err(CopyImplementationError::InfrigingField( + field.name)) + } + } + struct_def + } + ty::TyEnum(enum_def, substs) => { + for variant in &enum_def.variants { + for field in &variant.fields { + let field_ty = field.ty(tcx, substs); + if infcx.type_moves_by_default(field_ty, span) { + return Err(CopyImplementationError::InfrigingVariant( + variant.name)) + } + } + } + enum_def + } + _ => return Err(CopyImplementationError::NotAnAdt), + }; + + if adt.has_dtor() { + return Err(CopyImplementationError::HasDestructor) + } + + Ok(()) + } +} + +impl<'tcx> TyCtxt<'tcx> { + pub fn pat_contains_ref_binding(&self, pat: &hir::Pat) -> Option { + pat_util::pat_contains_ref_binding(&self.def_map, pat) + } + + pub fn arm_contains_ref_binding(&self, arm: &hir::Arm) -> Option { + pat_util::arm_contains_ref_binding(&self.def_map, arm) + } + + /// Returns the type of element at index `i` in tuple or tuple-like type `t`. + /// For an enum `t`, `variant` is None only if `t` is a univariant enum. + pub fn positional_element_ty(&self, + ty: Ty<'tcx>, + i: usize, + variant: Option) -> Option> { + match (&ty.sty, variant) { + (&TyStruct(def, substs), None) => { + def.struct_variant().fields.get(i).map(|f| f.ty(self, substs)) + } + (&TyEnum(def, substs), Some(vid)) => { + def.variant_with_id(vid).fields.get(i).map(|f| f.ty(self, substs)) + } + (&TyEnum(def, substs), None) => { + assert!(def.is_univariant()); + def.variants[0].fields.get(i).map(|f| f.ty(self, substs)) + } + (&TyTuple(ref v), None) => v.get(i).cloned(), + _ => None + } + } + + /// Returns the type of element at field `n` in struct or struct-like type `t`. + /// For an enum `t`, `variant` must be some def id. + pub fn named_element_ty(&self, + ty: Ty<'tcx>, + n: Name, + variant: Option) -> Option> { + match (&ty.sty, variant) { + (&TyStruct(def, substs), None) => { + def.struct_variant().find_field_named(n).map(|f| f.ty(self, substs)) + } + (&TyEnum(def, substs), Some(vid)) => { + def.variant_with_id(vid).find_field_named(n).map(|f| f.ty(self, substs)) + } + _ => return None + } + } + + /// Returns the IntType representation. + /// This used to ensure `int_ty` doesn't contain `usize` and `isize` + /// by converting them to their actual types. That doesn't happen anymore. + pub fn enum_repr_type(&self, opt_hint: Option<&attr::ReprAttr>) -> attr::IntType { + match opt_hint { + // Feed in the given type + Some(&attr::ReprInt(_, int_t)) => int_t, + // ... but provide sensible default if none provided + // + // NB. Historically `fn enum_variants` generate i64 here, while + // rustc_typeck::check would generate isize. + _ => SignedInt(ast::IntTy::Is), + } + } + + /// Returns the deeply last field of nested structures, or the same type, + /// if not a structure at all. Corresponds to the only possible unsized + /// field, and its type can be used to determine unsizing strategy. + pub fn struct_tail(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { + while let TyStruct(def, substs) = ty.sty { + match def.struct_variant().fields.last() { + Some(f) => ty = f.ty(self, substs), + None => break + } + } + ty + } + + /// Same as applying struct_tail on `source` and `target`, but only + /// keeps going as long as the two types are instances of the same + /// structure definitions. + /// For `(Foo>, Foo)`, the result will be `(Foo, Trait)`, + /// whereas struct_tail produces `T`, and `Trait`, respectively. + pub fn struct_lockstep_tails(&self, + source: Ty<'tcx>, + target: Ty<'tcx>) + -> (Ty<'tcx>, Ty<'tcx>) { + let (mut a, mut b) = (source, target); + while let (&TyStruct(a_def, a_substs), &TyStruct(b_def, b_substs)) = (&a.sty, &b.sty) { + if a_def != b_def { + break; + } + if let Some(f) = a_def.struct_variant().fields.last() { + a = f.ty(self, a_substs); + b = f.ty(self, b_substs); + } else { + break; + } + } + (a, b) + } + + /// Returns the repeat count for a repeating vector expression. + pub fn eval_repeat_count(&self, count_expr: &hir::Expr) -> usize { + let hint = UncheckedExprHint(self.types.usize); + match const_eval::eval_const_expr_partial(self, count_expr, hint, None) { + Ok(ConstVal::Integral(ConstInt::Usize(count))) => { + let val = count.as_u64(self.sess.target.uint_type); + assert_eq!(val as usize as u64, val); + val as usize + }, + Ok(const_val) => { + span_err!(self.sess, count_expr.span, E0306, + "expected positive integer for repeat count, found {}", + const_val.description()); + 0 + } + Err(err) => { + let err_msg = match count_expr.node { + hir::ExprPath(None, hir::Path { + global: false, + ref segments, + .. + }) if segments.len() == 1 => + format!("found variable"), + _ => match err.kind { + ErrKind::MiscCatchAll => format!("but found {}", err.description()), + _ => format!("but {}", err.description()) + } + }; + span_err!(self.sess, count_expr.span, E0307, + "expected constant integer for repeat count, {}", err_msg); + 0 + } + } + } + + /// Given a set of predicates that apply to an object type, returns + /// the region bounds that the (erased) `Self` type must + /// outlive. Precisely *because* the `Self` type is erased, the + /// parameter `erased_self_ty` must be supplied to indicate what type + /// has been used to represent `Self` in the predicates + /// themselves. This should really be a unique type; `FreshTy(0)` is a + /// popular choice. + /// + /// NB: in some cases, particularly around higher-ranked bounds, + /// this function returns a kind of conservative approximation. + /// That is, all regions returned by this function are definitely + /// required, but there may be other region bounds that are not + /// returned, as well as requirements like `for<'a> T: 'a`. + /// + /// Requires that trait definitions have been processed so that we can + /// elaborate predicates and walk supertraits. + pub fn required_region_bounds(&self, + erased_self_ty: Ty<'tcx>, + predicates: Vec>) + -> Vec { + debug!("required_region_bounds(erased_self_ty={:?}, predicates={:?})", + erased_self_ty, + predicates); + + assert!(!erased_self_ty.has_escaping_regions()); + + traits::elaborate_predicates(self, predicates) + .filter_map(|predicate| { + match predicate { + ty::Predicate::Projection(..) | + ty::Predicate::Trait(..) | + ty::Predicate::Equate(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | + ty::Predicate::RegionOutlives(..) => { + None + } + ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t, r))) => { + // Search for a bound of the form `erased_self_ty + // : 'a`, but be wary of something like `for<'a> + // erased_self_ty : 'a` (we interpret a + // higher-ranked bound like that as 'static, + // though at present the code in `fulfill.rs` + // considers such bounds to be unsatisfiable, so + // it's kind of a moot point since you could never + // construct such an object, but this seems + // correct even if that code changes). + if t == erased_self_ty && !r.has_escaping_regions() { + Some(r) + } else { + None + } + } + } + }) + .collect() + } + + /// Creates a hash of the type `Ty` which will be the same no matter what crate + /// context it's calculated within. This is used by the `type_id` intrinsic. + pub fn hash_crate_independent(&self, ty: Ty<'tcx>, svh: &Svh) -> u64 { + let mut state = SipHasher::new(); + helper(self, ty, svh, &mut state); + return state.finish(); + + fn helper<'tcx>(tcx: &TyCtxt<'tcx>, ty: Ty<'tcx>, svh: &Svh, + state: &mut SipHasher) { + macro_rules! byte { ($b:expr) => { ($b as u8).hash(state) } } + macro_rules! hash { ($e:expr) => { $e.hash(state) } } + + let region = |state: &mut SipHasher, r: ty::Region| { + match r { + ty::ReStatic => {} + ty::ReLateBound(db, ty::BrAnon(i)) => { + db.hash(state); + i.hash(state); + } + ty::ReEmpty | + ty::ReEarlyBound(..) | + ty::ReLateBound(..) | + ty::ReFree(..) | + ty::ReScope(..) | + ty::ReVar(..) | + ty::ReSkolemized(..) => { + tcx.sess.bug("unexpected region found when hashing a type") + } + } + }; + let did = |state: &mut SipHasher, did: DefId| { + let h = if did.is_local() { + svh.clone() + } else { + tcx.sess.cstore.crate_hash(did.krate) + }; + h.as_str().hash(state); + did.index.hash(state); + }; + let mt = |state: &mut SipHasher, mt: TypeAndMut| { + mt.mutbl.hash(state); + }; + let fn_sig = |state: &mut SipHasher, sig: &ty::Binder>| { + let sig = tcx.anonymize_late_bound_regions(sig).0; + for a in &sig.inputs { helper(tcx, *a, svh, state); } + if let ty::FnConverging(output) = sig.output { + helper(tcx, output, svh, state); + } + }; + ty.maybe_walk(|ty| { + match ty.sty { + TyBool => byte!(2), + TyChar => byte!(3), + TyInt(i) => { + byte!(4); + hash!(i); + } + TyUint(u) => { + byte!(5); + hash!(u); + } + TyFloat(f) => { + byte!(6); + hash!(f); + } + TyStr => { + byte!(7); + } + TyEnum(d, _) => { + byte!(8); + did(state, d.did); + } + TyBox(_) => { + byte!(9); + } + TyArray(_, n) => { + byte!(10); + n.hash(state); + } + TySlice(_) => { + byte!(11); + } + TyRawPtr(m) => { + byte!(12); + mt(state, m); + } + TyRef(r, m) => { + byte!(13); + region(state, *r); + mt(state, m); + } + TyFnDef(def_id, _, _) => { + byte!(14); + hash!(def_id); + } + TyFnPtr(ref b) => { + byte!(15); + hash!(b.unsafety); + hash!(b.abi); + fn_sig(state, &b.sig); + return false; + } + TyTrait(ref data) => { + byte!(17); + did(state, data.principal_def_id()); + hash!(data.bounds); + + let principal = tcx.anonymize_late_bound_regions(&data.principal).0; + for subty in &principal.substs.types { + helper(tcx, subty, svh, state); + } + + return false; + } + TyStruct(d, _) => { + byte!(18); + did(state, d.did); + } + TyTuple(ref inner) => { + byte!(19); + hash!(inner.len()); + } + TyParam(p) => { + byte!(20); + hash!(p.space); + hash!(p.idx); + hash!(p.name.as_str()); + } + TyInfer(_) => unreachable!(), + TyError => byte!(21), + TyClosure(d, _) => { + byte!(22); + did(state, d); + } + TyProjection(ref data) => { + byte!(23); + did(state, data.trait_ref.def_id); + hash!(data.item_name.as_str()); + } + } + true + }); + } + } + + /// Returns true if this ADT is a dtorck type. + /// + /// Invoking the destructor of a dtorck type during usual cleanup + /// (e.g. the glue emitted for stack unwinding) requires all + /// lifetimes in the type-structure of `adt` to strictly outlive + /// the adt value itself. + /// + /// If `adt` is not dtorck, then the adt's destructor can be + /// invoked even when there are lifetimes in the type-structure of + /// `adt` that do not strictly outlive the adt value itself. + /// (This allows programs to make cyclic structures without + /// resorting to unasfe means; see RFCs 769 and 1238). + pub fn is_adt_dtorck(&self, adt: ty::AdtDef<'tcx>) -> bool { + let dtor_method = match adt.destructor() { + Some(dtor) => dtor, + None => return false + }; + + // RFC 1238: if the destructor method is tagged with the + // attribute `unsafe_destructor_blind_to_params`, then the + // compiler is being instructed to *assume* that the + // destructor will not access borrowed data, + // even if such data is otherwise reachable. + // + // Such access can be in plain sight (e.g. dereferencing + // `*foo.0` of `Foo<'a>(&'a u32)`) or indirectly hidden + // (e.g. calling `foo.0.clone()` of `Foo`). + return !self.has_attr(dtor_method, "unsafe_destructor_blind_to_params"); + } +} + +impl<'tcx> ty::TyS<'tcx> { + fn impls_bound<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, + bound: ty::BuiltinBound, + span: Span) + -> bool + { + let tcx = param_env.tcx; + let infcx = infer::new_infer_ctxt(tcx, + &tcx.tables, + Some(param_env.clone()), + ProjectionMode::Topmost); + + let is_impld = traits::type_known_to_meet_builtin_bound(&infcx, + self, bound, span); + + debug!("Ty::impls_bound({:?}, {:?}) = {:?}", + self, bound, is_impld); + + is_impld + } + + // FIXME (@jroesch): I made this public to use it, not sure if should be private + pub fn moves_by_default<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, + span: Span) -> bool { + if self.flags.get().intersects(TypeFlags::MOVENESS_CACHED) { + return self.flags.get().intersects(TypeFlags::MOVES_BY_DEFAULT); + } + + assert!(!self.needs_infer()); + + // Fast-path for primitive types + let result = match self.sty { + TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | + TyRawPtr(..) | TyFnDef(..) | TyFnPtr(_) | TyRef(_, TypeAndMut { + mutbl: hir::MutImmutable, .. + }) => Some(false), + + TyStr | TyBox(..) | TyRef(_, TypeAndMut { + mutbl: hir::MutMutable, .. + }) => Some(true), + + TyArray(..) | TySlice(_) | TyTrait(..) | TyTuple(..) | + TyClosure(..) | TyEnum(..) | TyStruct(..) | + TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None + }.unwrap_or_else(|| !self.impls_bound(param_env, ty::BoundCopy, span)); + + if !self.has_param_types() && !self.has_self_ty() { + self.flags.set(self.flags.get() | if result { + TypeFlags::MOVENESS_CACHED | TypeFlags::MOVES_BY_DEFAULT + } else { + TypeFlags::MOVENESS_CACHED + }); + } + + result + } + + #[inline] + pub fn is_sized<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, + span: Span) -> bool + { + if self.flags.get().intersects(TypeFlags::SIZEDNESS_CACHED) { + return self.flags.get().intersects(TypeFlags::IS_SIZED); + } + + self.is_sized_uncached(param_env, span) + } + + fn is_sized_uncached<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, + span: Span) -> bool { + assert!(!self.needs_infer()); + + // Fast-path for primitive types + let result = match self.sty { + TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | + TyBox(..) | TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) | + TyArray(..) | TyTuple(..) | TyClosure(..) => Some(true), + + TyStr | TyTrait(..) | TySlice(_) => Some(false), + + TyEnum(..) | TyStruct(..) | TyProjection(..) | TyParam(..) | + TyInfer(..) | TyError => None + }.unwrap_or_else(|| self.impls_bound(param_env, ty::BoundSized, span)); + + if !self.has_param_types() && !self.has_self_ty() { + self.flags.set(self.flags.get() | if result { + TypeFlags::SIZEDNESS_CACHED | TypeFlags::IS_SIZED + } else { + TypeFlags::SIZEDNESS_CACHED + }); + } + + result + } + + + /// Check whether a type is representable. This means it cannot contain unboxed + /// structural recursion. This check is needed for structs and enums. + pub fn is_representable(&'tcx self, cx: &TyCtxt<'tcx>, sp: Span) -> Representability { + + // Iterate until something non-representable is found + fn find_nonrepresentable<'tcx, It: Iterator>>(cx: &TyCtxt<'tcx>, + sp: Span, + seen: &mut Vec>, + iter: It) + -> Representability { + iter.fold(Representability::Representable, + |r, ty| cmp::max(r, is_type_structurally_recursive(cx, sp, seen, ty))) + } + + fn are_inner_types_recursive<'tcx>(cx: &TyCtxt<'tcx>, sp: Span, + seen: &mut Vec>, ty: Ty<'tcx>) + -> Representability { + match ty.sty { + TyTuple(ref ts) => { + find_nonrepresentable(cx, sp, seen, ts.iter().cloned()) + } + // Fixed-length vectors. + // FIXME(#11924) Behavior undecided for zero-length vectors. + TyArray(ty, _) => { + is_type_structurally_recursive(cx, sp, seen, ty) + } + TyStruct(def, substs) | TyEnum(def, substs) => { + find_nonrepresentable(cx, + sp, + seen, + def.all_fields().map(|f| f.ty(cx, substs))) + } + TyClosure(..) => { + // this check is run on type definitions, so we don't expect + // to see closure types + cx.sess.bug(&format!("requires check invoked on inapplicable type: {:?}", ty)) + } + _ => Representability::Representable, + } + } + + fn same_struct_or_enum<'tcx>(ty: Ty<'tcx>, def: ty::AdtDef<'tcx>) -> bool { + match ty.sty { + TyStruct(ty_def, _) | TyEnum(ty_def, _) => { + ty_def == def + } + _ => false + } + } + + fn same_type<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { + match (&a.sty, &b.sty) { + (&TyStruct(did_a, ref substs_a), &TyStruct(did_b, ref substs_b)) | + (&TyEnum(did_a, ref substs_a), &TyEnum(did_b, ref substs_b)) => { + if did_a != did_b { + return false; + } + + let types_a = substs_a.types.get_slice(subst::TypeSpace); + let types_b = substs_b.types.get_slice(subst::TypeSpace); + + let mut pairs = types_a.iter().zip(types_b); + + pairs.all(|(&a, &b)| same_type(a, b)) + } + _ => { + a == b + } + } + } + + // Does the type `ty` directly (without indirection through a pointer) + // contain any types on stack `seen`? + fn is_type_structurally_recursive<'tcx>(cx: &TyCtxt<'tcx>, + sp: Span, + seen: &mut Vec>, + ty: Ty<'tcx>) -> Representability { + debug!("is_type_structurally_recursive: {:?}", ty); + + match ty.sty { + TyStruct(def, _) | TyEnum(def, _) => { + { + // Iterate through stack of previously seen types. + let mut iter = seen.iter(); + + // The first item in `seen` is the type we are actually curious about. + // We want to return SelfRecursive if this type contains itself. + // It is important that we DON'T take generic parameters into account + // for this check, so that Bar in this example counts as SelfRecursive: + // + // struct Foo; + // struct Bar { x: Bar } + + match iter.next() { + Some(&seen_type) => { + if same_struct_or_enum(seen_type, def) { + debug!("SelfRecursive: {:?} contains {:?}", + seen_type, + ty); + return Representability::SelfRecursive; + } + } + None => {} + } + + // We also need to know whether the first item contains other types + // that are structurally recursive. If we don't catch this case, we + // will recurse infinitely for some inputs. + // + // It is important that we DO take generic parameters into account + // here, so that code like this is considered SelfRecursive, not + // ContainsRecursive: + // + // struct Foo { Option> } + + for &seen_type in iter { + if same_type(ty, seen_type) { + debug!("ContainsRecursive: {:?} contains {:?}", + seen_type, + ty); + return Representability::ContainsRecursive; + } + } + } + + // For structs and enums, track all previously seen types by pushing them + // onto the 'seen' stack. + seen.push(ty); + let out = are_inner_types_recursive(cx, sp, seen, ty); + seen.pop(); + out + } + _ => { + // No need to push in other cases. + are_inner_types_recursive(cx, sp, seen, ty) + } + } + } + + debug!("is_type_representable: {:?}", self); + + // To avoid a stack overflow when checking an enum variant or struct that + // contains a different, structurally recursive type, maintain a stack + // of seen types and check recursion for each of them (issues #3008, #3779). + let mut seen: Vec = Vec::new(); + let r = is_type_structurally_recursive(cx, sp, &mut seen, self); + debug!("is_type_representable: {:?} is {:?}", self, r); + r + } +} diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs new file mode 100644 index 00000000000..fa7c9b78231 --- /dev/null +++ b/src/librustc/ty/walk.rs @@ -0,0 +1,129 @@ +// Copyright 2012-2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! An iterator over the type substructure. +//! WARNING: this does not keep track of the region depth. + +use ty::{self, Ty}; +use std::iter::Iterator; +use std::vec::IntoIter; + +pub struct TypeWalker<'tcx> { + stack: Vec>, + last_subtree: usize, +} + +impl<'tcx> TypeWalker<'tcx> { + pub fn new(ty: Ty<'tcx>) -> TypeWalker<'tcx> { + TypeWalker { stack: vec!(ty), last_subtree: 1, } + } + + /// Skips the subtree of types corresponding to the last type + /// returned by `next()`. + /// + /// Example: Imagine you are walking `Foo, usize>`. + /// + /// ``` + /// let mut iter: TypeWalker = ...; + /// iter.next(); // yields Foo + /// iter.next(); // yields Bar + /// iter.skip_current_subtree(); // skips int + /// iter.next(); // yields usize + /// ``` + pub fn skip_current_subtree(&mut self) { + self.stack.truncate(self.last_subtree); + } +} + +impl<'tcx> Iterator for TypeWalker<'tcx> { + type Item = Ty<'tcx>; + + fn next(&mut self) -> Option> { + debug!("next(): stack={:?}", self.stack); + match self.stack.pop() { + None => { + return None; + } + Some(ty) => { + self.last_subtree = self.stack.len(); + push_subtypes(&mut self.stack, ty); + debug!("next: stack={:?}", self.stack); + Some(ty) + } + } + } +} + +pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> IntoIter> { + let mut stack = vec![]; + push_subtypes(&mut stack, ty); + stack.into_iter() +} + +fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { + match parent_ty.sty { + ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | + ty::TyStr | ty::TyInfer(_) | ty::TyParam(_) | ty::TyError => { + } + ty::TyBox(ty) | ty::TyArray(ty, _) | ty::TySlice(ty) => { + stack.push(ty); + } + ty::TyRawPtr(ref mt) | ty::TyRef(_, ref mt) => { + stack.push(mt.ty); + } + ty::TyProjection(ref data) => { + push_reversed(stack, data.trait_ref.substs.types.as_slice()); + } + ty::TyTrait(box ty::TraitTy { ref principal, ref bounds }) => { + push_reversed(stack, principal.substs().types.as_slice()); + push_reversed(stack, &bounds.projection_bounds.iter().map(|pred| { + pred.0.ty + }).collect::>()); + } + ty::TyEnum(_, ref substs) | + ty::TyStruct(_, ref substs) => { + push_reversed(stack, substs.types.as_slice()); + } + ty::TyClosure(_, ref substs) => { + push_reversed(stack, substs.func_substs.types.as_slice()); + push_reversed(stack, &substs.upvar_tys); + } + ty::TyTuple(ref ts) => { + push_reversed(stack, ts); + } + ty::TyFnDef(_, substs, ref ft) => { + push_reversed(stack, substs.types.as_slice()); + push_sig_subtypes(stack, &ft.sig); + } + ty::TyFnPtr(ref ft) => { + push_sig_subtypes(stack, &ft.sig); + } + } +} + +fn push_sig_subtypes<'tcx>(stack: &mut Vec>, sig: &ty::PolyFnSig<'tcx>) { + match sig.0.output { + ty::FnConverging(output) => { stack.push(output); } + ty::FnDiverging => { } + } + push_reversed(stack, &sig.0.inputs); +} + +fn push_reversed<'tcx>(stack: &mut Vec>, tys: &[Ty<'tcx>]) { + // We push slices on the stack in reverse order so as to + // maintain a pre-order traversal. As of the time of this + // writing, the fact that the traversal is pre-order is not + // known to be significant to any code, but it seems like the + // natural order one would expect (basically, the order of the + // types as they are written). + for &ty in tys.iter().rev() { + stack.push(ty); + } +} diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs new file mode 100644 index 00000000000..e6c4e90babb --- /dev/null +++ b/src/librustc/ty/wf.rs @@ -0,0 +1,509 @@ +// Copyright 2012-2013 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use middle::def_id::DefId; +use infer::InferCtxt; +use ty::outlives::{self, Component}; +use ty::subst::Substs; +use traits; +use ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use std::iter::once; +use syntax::ast; +use syntax::codemap::Span; +use util::common::ErrorReported; + +/// Returns the set of obligations needed to make `ty` well-formed. +/// If `ty` contains unresolved inference variables, this may include +/// further WF obligations. However, if `ty` IS an unresolved +/// inference variable, returns `None`, because we are not able to +/// make any progress at all. This is to prevent "livelock" where we +/// say "$0 is WF if $0 is WF". +pub fn obligations<'a,'tcx>(infcx: &InferCtxt<'a, 'tcx>, + body_id: ast::NodeId, + ty: Ty<'tcx>, + span: Span) + -> Option>> +{ + let mut wf = WfPredicates { infcx: infcx, + body_id: body_id, + span: span, + out: vec![] }; + if wf.compute(ty) { + debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out); + let result = wf.normalize(); + debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", ty, body_id, result); + Some(result) + } else { + None // no progress made, return None + } +} + +/// Returns the obligations that make this trait reference +/// well-formed. For example, if there is a trait `Set` defined like +/// `trait Set`, then the trait reference `Foo: Set` is WF +/// if `Bar: Eq`. +pub fn trait_obligations<'a,'tcx>(infcx: &InferCtxt<'a, 'tcx>, + body_id: ast::NodeId, + trait_ref: &ty::TraitRef<'tcx>, + span: Span) + -> Vec> +{ + let mut wf = WfPredicates { infcx: infcx, body_id: body_id, span: span, out: vec![] }; + wf.compute_trait_ref(trait_ref); + wf.normalize() +} + +pub fn predicate_obligations<'a,'tcx>(infcx: &InferCtxt<'a, 'tcx>, + body_id: ast::NodeId, + predicate: &ty::Predicate<'tcx>, + span: Span) + -> Vec> +{ + let mut wf = WfPredicates { infcx: infcx, body_id: body_id, span: span, out: vec![] }; + + // (*) ok to skip binders, because wf code is prepared for it + match *predicate { + ty::Predicate::Trait(ref t) => { + wf.compute_trait_ref(&t.skip_binder().trait_ref); // (*) + } + ty::Predicate::Equate(ref t) => { + wf.compute(t.skip_binder().0); + wf.compute(t.skip_binder().1); + } + ty::Predicate::RegionOutlives(..) => { + } + ty::Predicate::TypeOutlives(ref t) => { + wf.compute(t.skip_binder().0); + } + ty::Predicate::Projection(ref t) => { + let t = t.skip_binder(); // (*) + wf.compute_projection(t.projection_ty); + wf.compute(t.ty); + } + ty::Predicate::WellFormed(t) => { + wf.compute(t); + } + ty::Predicate::ObjectSafe(_) => { + } + } + + wf.normalize() +} + +/// Implied bounds are region relationships that we deduce +/// automatically. The idea is that (e.g.) a caller must check that a +/// function's argument types are well-formed immediately before +/// calling that fn, and hence the *callee* can assume that its +/// argument types are well-formed. This may imply certain relationships +/// between generic parameters. For example: +/// +/// fn foo<'a,T>(x: &'a T) +/// +/// can only be called with a `'a` and `T` such that `&'a T` is WF. +/// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`. +#[derive(Debug)] +pub enum ImpliedBound<'tcx> { + RegionSubRegion(ty::Region, ty::Region), + RegionSubParam(ty::Region, ty::ParamTy), + RegionSubProjection(ty::Region, ty::ProjectionTy<'tcx>), +} + +/// Compute the implied bounds that a callee/impl can assume based on +/// the fact that caller/projector has ensured that `ty` is WF. See +/// the `ImpliedBound` type for more details. +pub fn implied_bounds<'a,'tcx>( + infcx: &'a InferCtxt<'a,'tcx>, + body_id: ast::NodeId, + ty: Ty<'tcx>, + span: Span) + -> Vec> +{ + // Sometimes when we ask what it takes for T: WF, we get back that + // U: WF is required; in that case, we push U onto this stack and + // process it next. Currently (at least) these resulting + // predicates are always guaranteed to be a subset of the original + // type, so we need not fear non-termination. + let mut wf_types = vec![ty]; + + let mut implied_bounds = vec![]; + + while let Some(ty) = wf_types.pop() { + // Compute the obligations for `ty` to be well-formed. If `ty` is + // an unresolved inference variable, just substituted an empty set + // -- because the return type here is going to be things we *add* + // to the environment, it's always ok for this set to be smaller + // than the ultimate set. (Note: normally there won't be + // unresolved inference variables here anyway, but there might be + // during typeck under some circumstances.) + let obligations = obligations(infcx, body_id, ty, span).unwrap_or(vec![]); + + // From the full set of obligations, just filter down to the + // region relationships. + implied_bounds.extend( + obligations + .into_iter() + .flat_map(|obligation| { + assert!(!obligation.has_escaping_regions()); + match obligation.predicate { + ty::Predicate::Trait(..) | + ty::Predicate::Equate(..) | + ty::Predicate::Projection(..) | + ty::Predicate::ObjectSafe(..) => + vec![], + + ty::Predicate::WellFormed(subty) => { + wf_types.push(subty); + vec![] + } + + ty::Predicate::RegionOutlives(ref data) => + match infcx.tcx.no_late_bound_regions(data) { + None => + vec![], + Some(ty::OutlivesPredicate(r_a, r_b)) => + vec![ImpliedBound::RegionSubRegion(r_b, r_a)], + }, + + ty::Predicate::TypeOutlives(ref data) => + match infcx.tcx.no_late_bound_regions(data) { + None => vec![], + Some(ty::OutlivesPredicate(ty_a, r_b)) => { + let components = outlives::components(infcx, ty_a); + implied_bounds_from_components(r_b, components) + } + }, + }})); + } + + implied_bounds +} + +/// When we have an implied bound that `T: 'a`, we can further break +/// this down to determine what relationships would have to hold for +/// `T: 'a` to hold. We get to assume that the caller has validated +/// those relationships. +fn implied_bounds_from_components<'tcx>(sub_region: ty::Region, + sup_components: Vec>) + -> Vec> +{ + sup_components + .into_iter() + .flat_map(|component| { + match component { + Component::Region(r) => + vec!(ImpliedBound::RegionSubRegion(sub_region, r)), + Component::Param(p) => + vec!(ImpliedBound::RegionSubParam(sub_region, p)), + Component::Projection(p) => + vec!(ImpliedBound::RegionSubProjection(sub_region, p)), + Component::EscapingProjection(_) => + // If the projection has escaping regions, don't + // try to infer any implied bounds even for its + // free components. This is conservative, because + // the caller will still have to prove that those + // free components outlive `sub_region`. But the + // idea is that the WAY that the caller proves + // that may change in the future and we want to + // give ourselves room to get smarter here. + vec!(), + Component::UnresolvedInferenceVariable(..) => + vec!(), + } + }) + .collect() +} + +struct WfPredicates<'a,'tcx:'a> { + infcx: &'a InferCtxt<'a, 'tcx>, + body_id: ast::NodeId, + span: Span, + out: Vec>, +} + +impl<'a,'tcx> WfPredicates<'a,'tcx> { + fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> { + traits::ObligationCause::new(self.span, self.body_id, code) + } + + fn normalize(&mut self) -> Vec> { + let cause = self.cause(traits::MiscObligation); + let infcx = &mut self.infcx; + self.out.iter() + .inspect(|pred| assert!(!pred.has_escaping_regions())) + .flat_map(|pred| { + let mut selcx = traits::SelectionContext::new(infcx); + let pred = traits::normalize(&mut selcx, cause.clone(), pred); + once(pred.value).chain(pred.obligations) + }) + .collect() + } + + /// Pushes the obligations required for `trait_ref` to be WF into + /// `self.out`. + fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>) { + let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs); + self.out.extend(obligations); + + let cause = self.cause(traits::MiscObligation); + self.out.extend( + trait_ref.substs.types + .as_slice() + .iter() + .filter(|ty| !ty.has_escaping_regions()) + .map(|ty| traits::Obligation::new(cause.clone(), + ty::Predicate::WellFormed(ty)))); + } + + /// Pushes the obligations required for `trait_ref::Item` to be WF + /// into `self.out`. + fn compute_projection(&mut self, data: ty::ProjectionTy<'tcx>) { + // A projection is well-formed if (a) the trait ref itself is + // WF WF and (b) the trait-ref holds. (It may also be + // normalizable and be WF that way.) + + self.compute_trait_ref(&data.trait_ref); + + if !data.has_escaping_regions() { + let predicate = data.trait_ref.to_predicate(); + let cause = self.cause(traits::ProjectionWf(data)); + self.out.push(traits::Obligation::new(cause, predicate)); + } + } + + /// Push new obligations into `out`. Returns true if it was able + /// to generate all the predicates needed to validate that `ty0` + /// is WF. Returns false if `ty0` is an unresolved type variable, + /// in which case we are not able to simplify at all. + fn compute(&mut self, ty0: Ty<'tcx>) -> bool { + let mut subtys = ty0.walk(); + while let Some(ty) = subtys.next() { + match ty.sty { + ty::TyBool | + ty::TyChar | + ty::TyInt(..) | + ty::TyUint(..) | + ty::TyFloat(..) | + ty::TyError | + ty::TyStr | + ty::TyParam(_) => { + // WfScalar, WfParameter, etc + } + + ty::TySlice(subty) | + ty::TyArray(subty, _) => { + if !subty.has_escaping_regions() { + let cause = self.cause(traits::SliceOrArrayElem); + match traits::trait_ref_for_builtin_bound(self.infcx.tcx, + ty::BoundSized, + subty) { + Ok(trait_ref) => { + self.out.push( + traits::Obligation::new(cause, + trait_ref.to_predicate())); + } + Err(ErrorReported) => { } + } + } + } + + ty::TyBox(_) | + ty::TyTuple(_) | + ty::TyRawPtr(_) => { + // simple cases that are WF if their type args are WF + } + + ty::TyProjection(data) => { + subtys.skip_current_subtree(); // subtree handled by compute_projection + self.compute_projection(data); + } + + ty::TyEnum(def, substs) | + ty::TyStruct(def, substs) => { + // WfNominalType + let obligations = self.nominal_obligations(def.did, substs); + self.out.extend(obligations); + } + + ty::TyRef(r, mt) => { + // WfReference + if !r.has_escaping_regions() && !mt.ty.has_escaping_regions() { + let cause = self.cause(traits::ReferenceOutlivesReferent(ty)); + self.out.push( + traits::Obligation::new( + cause, + ty::Predicate::TypeOutlives( + ty::Binder( + ty::OutlivesPredicate(mt.ty, *r))))); + } + } + + ty::TyClosure(..) => { + // the types in a closure are always the types of + // local variables (or possibly references to local + // variables), we'll walk those. + // + // (Though, local variables are probably not + // needed, as they are separately checked w/r/t + // WFedness.) + } + + ty::TyFnDef(..) | ty::TyFnPtr(_) => { + // let the loop iterate into the argument/return + // types appearing in the fn signature + } + + ty::TyTrait(ref data) => { + // WfObject + // + // Here, we defer WF checking due to higher-ranked + // regions. This is perhaps not ideal. + self.from_object_ty(ty, data); + + // FIXME(#27579) RFC also considers adding trait + // obligations that don't refer to Self and + // checking those + + let cause = self.cause(traits::MiscObligation); + self.out.push( + traits::Obligation::new( + cause, + ty::Predicate::ObjectSafe(data.principal_def_id()))); + } + + // Inference variables are the complicated case, since we don't + // know what type they are. We do two things: + // + // 1. Check if they have been resolved, and if so proceed with + // THAT type. + // 2. If not, check whether this is the type that we + // started with (ty0). In that case, we've made no + // progress at all, so return false. Otherwise, + // we've at least simplified things (i.e., we went + // from `Vec<$0>: WF` to `$0: WF`, so we can + // register a pending obligation and keep + // moving. (Goal is that an "inductive hypothesis" + // is satisfied to ensure termination.) + ty::TyInfer(_) => { + let ty = self.infcx.shallow_resolve(ty); + if let ty::TyInfer(_) = ty.sty { // not yet resolved... + if ty == ty0 { // ...this is the type we started from! no progress. + return false; + } + + let cause = self.cause(traits::MiscObligation); + self.out.push( // ...not the type we started from, so we made progress. + traits::Obligation::new(cause, ty::Predicate::WellFormed(ty))); + } else { + // Yes, resolved, proceed with the + // result. Should never return false because + // `ty` is not a TyInfer. + assert!(self.compute(ty)); + } + } + } + } + + // if we made it through that loop above, we made progress! + return true; + } + + fn nominal_obligations(&mut self, + def_id: DefId, + substs: &Substs<'tcx>) + -> Vec> + { + let predicates = + self.infcx.tcx.lookup_predicates(def_id) + .instantiate(self.infcx.tcx, substs); + let cause = self.cause(traits::ItemObligation(def_id)); + predicates.predicates + .into_iter() + .map(|pred| traits::Obligation::new(cause.clone(), pred)) + .filter(|pred| !pred.has_escaping_regions()) + .collect() + } + + fn from_object_ty(&mut self, ty: Ty<'tcx>, data: &ty::TraitTy<'tcx>) { + // Imagine a type like this: + // + // trait Foo { } + // trait Bar<'c> : 'c { } + // + // &'b (Foo+'c+Bar<'d>) + // ^ + // + // In this case, the following relationships must hold: + // + // 'b <= 'c + // 'd <= 'c + // + // The first conditions is due to the normal region pointer + // rules, which say that a reference cannot outlive its + // referent. + // + // The final condition may be a bit surprising. In particular, + // you may expect that it would have been `'c <= 'd`, since + // usually lifetimes of outer things are conservative + // approximations for inner things. However, it works somewhat + // differently with trait objects: here the idea is that if the + // user specifies a region bound (`'c`, in this case) it is the + // "master bound" that *implies* that bounds from other traits are + // all met. (Remember that *all bounds* in a type like + // `Foo+Bar+Zed` must be met, not just one, hence if we write + // `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and + // 'y.) + // + // Note: in fact we only permit builtin traits, not `Bar<'d>`, I + // am looking forward to the future here. + + if !data.has_escaping_regions() { + let implicit_bounds = + object_region_bounds(self.infcx.tcx, + &data.principal, + data.bounds.builtin_bounds); + + let explicit_bound = data.bounds.region_bound; + + for implicit_bound in implicit_bounds { + let cause = self.cause(traits::ReferenceOutlivesReferent(ty)); + let outlives = ty::Binder(ty::OutlivesPredicate(explicit_bound, implicit_bound)); + self.out.push(traits::Obligation::new(cause, outlives.to_predicate())); + } + } + } +} + +/// Given an object type like `SomeTrait+Send`, computes the lifetime +/// bounds that must hold on the elided self type. These are derived +/// from the declarations of `SomeTrait`, `Send`, and friends -- if +/// they declare `trait SomeTrait : 'static`, for example, then +/// `'static` would appear in the list. The hard work is done by +/// `ty::required_region_bounds`, see that for more information. +pub fn object_region_bounds<'tcx>( + tcx: &TyCtxt<'tcx>, + principal: &ty::PolyTraitRef<'tcx>, + others: ty::BuiltinBounds) + -> Vec +{ + // Since we don't actually *know* the self type for an object, + // this "open(err)" serves as a kind of dummy standin -- basically + // a skolemized type. + let open_ty = tcx.mk_infer(ty::FreshTy(0)); + + // Note that we preserve the overall binding levels here. + assert!(!open_ty.has_escaping_regions()); + let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty)); + let trait_refs = vec!(ty::Binder(ty::TraitRef::new(principal.0.def_id, substs))); + + let mut predicates = others.to_predicates(tcx, open_ty); + predicates.extend(trait_refs.iter().map(|t| t.to_predicate())); + + tcx.required_region_bounds(open_ty, predicates) +} diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index f67346fe1f9..20f16a1d255 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -10,14 +10,14 @@ use middle::def_id::DefId; -use middle::ty::subst::{self, Subst}; -use middle::ty::{BrAnon, BrEnv, BrFresh, BrNamed}; -use middle::ty::{TyBool, TyChar, TyStruct, TyEnum}; -use middle::ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr}; -use middle::ty::{TyParam, TyRawPtr, TyRef, TyTuple}; -use middle::ty::TyClosure; -use middle::ty::{TyBox, TyTrait, TyInt, TyUint, TyInfer}; -use middle::ty::{self, Ty, TyCtxt, TypeFoldable}; +use ty::subst::{self, Subst}; +use ty::{BrAnon, BrEnv, BrFresh, BrNamed}; +use ty::{TyBool, TyChar, TyStruct, TyEnum}; +use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr}; +use ty::{TyParam, TyRawPtr, TyRef, TyTuple}; +use ty::TyClosure; +use ty::{TyBox, TyTrait, TyInt, TyUint, TyInfer}; +use ty::{self, Ty, TyCtxt, TypeFoldable}; use std::fmt; use syntax::abi::Abi; diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 9186765e6d0..aa2b7ed2cde 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -22,12 +22,12 @@ use borrowck::*; use borrowck::InteriorKind::{InteriorElement, InteriorField}; use rustc::middle::expr_use_visitor as euv; use rustc::middle::expr_use_visitor::MutateMode; -use rustc::middle::infer; +use rustc::infer; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; use rustc::middle::region; -use rustc::middle::ty::{self, TyCtxt}; -use rustc::middle::traits::ProjectionMode; +use rustc::ty::{self, TyCtxt}; +use rustc::traits::ProjectionMode; use syntax::ast; use syntax::codemap::Span; use rustc_front::hir; diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs index 3d6e9c8868c..2d38b665cf9 100644 --- a/src/librustc_borrowck/borrowck/fragments.rs +++ b/src/librustc_borrowck/borrowck/fragments.rs @@ -21,7 +21,7 @@ use borrowck::LoanPathElem::{LpDeref, LpInterior}; use borrowck::move_data::InvalidMovePathIndex; use borrowck::move_data::{MoveData, MovePathIndex}; use rustc::middle::def_id::{DefId}; -use rustc::middle::ty::{self, TyCtxt}; +use rustc::ty::{self, TyCtxt}; use rustc::middle::mem_categorization as mc; use std::mem; diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index 4e507284a1b..107109c9115 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -18,7 +18,7 @@ use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; use rustc::middle::mem_categorization::InteriorOffsetKind as Kind; -use rustc::middle::ty; +use rustc::ty; use std::rc::Rc; use syntax::ast; diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs index 84dce6d3570..c2492bba624 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs @@ -16,7 +16,7 @@ use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; use rustc::middle::region; -use rustc::middle::ty; +use rustc::ty; use syntax::ast; use syntax::codemap::Span; diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 2d255c05454..247f8121de7 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -19,12 +19,12 @@ use borrowck::*; use borrowck::move_data::MoveData; use rustc::middle::expr_use_visitor as euv; -use rustc::middle::infer; +use rustc::infer; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; use rustc::middle::region; -use rustc::middle::ty::{self, TyCtxt}; -use rustc::middle::traits::ProjectionMode; +use rustc::ty::{self, TyCtxt}; +use rustc::traits::ProjectionMode; use syntax::ast; use syntax::codemap::Span; diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index 4cb9673785e..f49554289b3 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -12,7 +12,7 @@ use borrowck::BorrowckCtxt; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; use rustc::middle::mem_categorization::InteriorOffsetKind as Kind; -use rustc::middle::ty; +use rustc::ty; use syntax::ast; use syntax::codemap; use syntax::errors::DiagnosticBuilder; diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs index 2a0d8ef2766..ee8c3aff2ec 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs @@ -14,7 +14,7 @@ use borrowck::*; use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; -use rustc::middle::ty; +use rustc::ty; use syntax::codemap::Span; use borrowck::ToInteriorKind; diff --git a/src/librustc_borrowck/borrowck/mir/dataflow.rs b/src/librustc_borrowck/borrowck/mir/dataflow.rs index 3c3a60b995f..a8176c060a1 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow.rs @@ -10,7 +10,7 @@ use syntax::attr::AttrMetaMethods; -use rustc::middle::ty; +use rustc::ty::TyCtxt; use rustc::mir::repr::{self, Mir}; use std::io; @@ -459,7 +459,7 @@ impl DataflowState { impl<'tcx> DataflowState> { - pub fn new_move_analysis(mir: &Mir<'tcx>, tcx: &ty::TyCtxt<'tcx>) -> Self { + pub fn new_move_analysis(mir: &Mir<'tcx>, tcx: &TyCtxt<'tcx>) -> Self { let move_data = MoveData::gather_moves(mir, tcx); DataflowState::new(mir, move_data) } diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index 46eb3d3ca03..dbe58799341 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -9,7 +9,7 @@ // except according to those terms. -use rustc::middle::ty::TyCtxt; +use rustc::ty::TyCtxt; use rustc::mir::repr::*; use rustc::util::nodemap::FnvHashMap; diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index bb2fe7acb95..d985359a3dd 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -23,7 +23,7 @@ use self::InteriorKind::*; use rustc::dep_graph::DepNode; use rustc::front::map as hir_map; use rustc::front::map::blocks::FnParts; -use rustc::middle::cfg; +use rustc::cfg; use rustc::middle::dataflow::DataFlowContext; use rustc::middle::dataflow::BitwiseOperator; use rustc::middle::dataflow::DataFlowOperator; @@ -34,7 +34,7 @@ use rustc::middle::free_region::FreeRegionMap; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; use rustc::middle::region; -use rustc::middle::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, Ty, TyCtxt}; use std::fmt; use std::mem; diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index 4c645d4bb69..00274fe1a04 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -14,14 +14,14 @@ pub use self::MoveKind::*; use borrowck::*; -use rustc::middle::cfg; +use rustc::cfg; use rustc::middle::dataflow::DataFlowContext; use rustc::middle::dataflow::BitwiseOperator; use rustc::middle::dataflow::DataFlowOperator; use rustc::middle::dataflow::KillFrom; use rustc::middle::expr_use_visitor as euv; use rustc::middle::expr_use_visitor::MutateMode; -use rustc::middle::ty::TyCtxt; +use rustc::ty::TyCtxt; use rustc::util::nodemap::{FnvHashMap, NodeSet}; use std::cell::RefCell; diff --git a/src/librustc_borrowck/graphviz.rs b/src/librustc_borrowck/graphviz.rs index fd23772bcda..0da9525efd8 100644 --- a/src/librustc_borrowck/graphviz.rs +++ b/src/librustc_borrowck/graphviz.rs @@ -14,13 +14,13 @@ pub use self::Variant::*; -pub use rustc::middle::cfg::graphviz::{Node, Edge}; -use rustc::middle::cfg::graphviz as cfg_dot; +pub use rustc::cfg::graphviz::{Node, Edge}; +use rustc::cfg::graphviz as cfg_dot; use borrowck; use borrowck::{BorrowckCtxt, LoanPath}; use dot; -use rustc::middle::cfg::CFGIndex; +use rustc::cfg::CFGIndex; use rustc::middle::dataflow::{DataFlowOperator, DataFlowContext, EntryOrExit}; use std::rc::Rc; use dot::IntoCow; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 96e819ea91f..11ee2a4fbc3 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -17,9 +17,9 @@ use rustc::session::{Session, CompileResult, compile_result_from_err_count}; use rustc::session::config::{self, Input, OutputFilenames, OutputType}; use rustc::session::search_paths::PathKind; use rustc::lint; -use rustc::middle::{self, dependency_format, stability, ty, reachable}; +use rustc::middle::{self, dependency_format, stability, reachable}; use rustc::middle::privacy::AccessLevels; -use rustc::middle::ty::TyCtxt; +use rustc::ty::{self, TyCtxt}; use rustc::util::common::time; use rustc::util::nodemap::NodeSet; use rustc_back::sha2::{Sha256, Digest}; diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 726dd02dd25..31345cfdc41 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -20,9 +20,9 @@ use rustc_trans::back::link; use {driver, abort_on_err}; use rustc::dep_graph::DepGraph; -use rustc::middle::ty::{self, TyCtxt}; -use rustc::middle::cfg; -use rustc::middle::cfg::graphviz::LabelledCFG; +use rustc::ty::{self, TyCtxt}; +use rustc::cfg; +use rustc::cfg::graphviz::LabelledCFG; use rustc::session::Session; use rustc::session::config::Input; use rustc_borrowck as borrowck; diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 6bca4ff481d..8620d5e1fd0 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -14,21 +14,21 @@ use driver; use rustc::dep_graph::DepGraph; use rustc_lint; use rustc_resolve as resolve; -use rustc_typeck::middle::lang_items; -use rustc_typeck::middle::free_region::FreeRegionMap; -use rustc_typeck::middle::region::{self, CodeExtent}; -use rustc_typeck::middle::region::CodeExtentData; -use rustc_typeck::middle::resolve_lifetime; -use rustc_typeck::middle::stability; -use rustc_typeck::middle::ty::subst; -use rustc_typeck::middle::ty::subst::Subst; -use rustc_typeck::middle::traits::ProjectionMode; -use rustc_typeck::middle::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc_typeck::middle::ty::relate::TypeRelation; -use rustc_typeck::middle::infer::{self, TypeOrigin}; -use rustc_typeck::middle::infer::lub::Lub; -use rustc_typeck::middle::infer::glb::Glb; -use rustc_typeck::middle::infer::sub::Sub; +use rustc::middle::lang_items; +use rustc::middle::free_region::FreeRegionMap; +use rustc::middle::region::{self, CodeExtent}; +use rustc::middle::region::CodeExtentData; +use rustc::middle::resolve_lifetime; +use rustc::middle::stability; +use rustc::ty::subst; +use rustc::ty::subst::Subst; +use rustc::traits::ProjectionMode; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::relate::TypeRelation; +use rustc::infer::{self, TypeOrigin}; +use rustc::infer::lub::Lub; +use rustc::infer::glb::Glb; +use rustc::infer::sub::Sub; use rustc_metadata::cstore::CStore; use rustc::front::map as hir_map; use rustc::session::{self, config}; diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index e399270197e..66d435a7581 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -9,7 +9,7 @@ // except according to those terms. use middle::def::Def; -use middle::ty; +use rustc::ty; use lint::{LateContext, LintContext, LintArray}; use lint::{LintPass, LateLintPass}; diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 66e19cf29bf..339c969b01f 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -28,14 +28,15 @@ //! Use the former for unit-like structs and the latter for structs with //! a `pub fn new()`. -use middle::{cfg, infer, stability, traits}; use middle::def::Def; use middle::cstore::CrateStore; use middle::def_id::DefId; -use middle::ty::subst::Substs; -use middle::ty::{self, Ty, TyCtxt}; -use middle::ty::adjustment; -use middle::traits::ProjectionMode; +use middle::stability; +use rustc::{cfg, infer}; +use rustc::ty::subst::Substs; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::adjustment; +use rustc::traits::{self, ProjectionMode}; use rustc::front::map as hir_map; use util::nodemap::{NodeSet}; use lint::{Level, LateContext, LintContext, LintArray, Lint}; diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 3dfd265c5a0..6322f592573 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -10,10 +10,10 @@ #![allow(non_snake_case)] -use middle::{infer}; use middle::def_id::DefId; -use middle::ty::subst::Substs; -use middle::ty::{self, Ty, TyCtxt}; +use rustc::infer; +use rustc::ty::subst::Substs; +use rustc::ty::{self, Ty, TyCtxt}; use middle::const_eval::{eval_const_expr_partial, ConstVal}; use middle::const_eval::EvalHint::ExprTypeChecked; use util::nodemap::{FnvHashSet}; diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 36ed06a6c00..9840cd4256f 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -9,8 +9,8 @@ // except according to those terms. use middle::pat_util; -use middle::ty; -use middle::ty::adjustment; +use rustc::ty; +use rustc::ty::adjustment; use util::nodemap::FnvHashMap; use lint::{LateContext, EarlyContext, LintContext, LintArray}; use lint::{LintPass, EarlyLintPass, LateLintPass}; diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index 4a74dc03fb4..60865888a54 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -27,14 +27,14 @@ use tydecode; use tyencode; use middle::cstore::{InlinedItem, InlinedItemRef}; -use middle::ty::adjustment; -use middle::ty::cast; +use rustc::ty::adjustment; +use rustc::ty::cast; use middle::const_qualif::ConstQualif; use middle::def::{self, Def}; use middle::def_id::DefId; use middle::region; -use middle::ty::subst; -use middle::ty::{self, Ty, TyCtxt}; +use rustc::ty::subst; +use rustc::ty::{self, Ty, TyCtxt}; use syntax::{ast, ast_util, codemap}; use syntax::ast::NodeIdAssigner; diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 25cc2f91753..b1142393268 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -17,7 +17,7 @@ use middle::cstore::{CrateStore, CrateSource, ChildItem, ExternCrate, FoundAst}; use middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference}; use middle::def; use middle::lang_items; -use middle::ty::{self, Ty, TyCtxt, VariantKind}; +use rustc::ty::{self, Ty, TyCtxt, VariantKind}; use middle::def_id::{DefId, DefIndex}; use rustc::front::map as hir_map; diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 47273b7f26a..e6f516ccd33 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -32,9 +32,9 @@ use middle::cstore::{DefLike, DlDef, DlField, DlImpl, tls}; use middle::def::Def; use middle::def_id::{DefId, DefIndex}; use middle::lang_items; -use middle::ty::subst; -use middle::ty::{ImplContainer, TraitContainer}; -use middle::ty::{self, Ty, TyCtxt, TypeFoldable, VariantKind}; +use rustc::ty::subst; +use rustc::ty::{ImplContainer, TraitContainer}; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, VariantKind}; use rustc_const_eval::ConstInt; diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 22b5297df43..0a23cdee23d 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -25,10 +25,10 @@ use middle::def; use middle::def_id::{CRATE_DEF_INDEX, DefId}; use middle::dependency_format::Linkage; use middle::stability; -use middle::ty::subst; -use middle::traits::specialization_graph; -use middle::ty::{self, Ty, TyCtxt}; -use middle::ty::util::IntTypeExt; +use rustc::ty::subst; +use rustc::traits::specialization_graph; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::util::IntTypeExt; use rustc::back::svh::Svh; use rustc::front::map::{LinkedPath, PathElem, PathElems}; diff --git a/src/librustc_metadata/tls_context.rs b/src/librustc_metadata/tls_context.rs index 2ba3e351c50..6ecd7a7f50a 100644 --- a/src/librustc_metadata/tls_context.rs +++ b/src/librustc_metadata/tls_context.rs @@ -15,8 +15,8 @@ use rbml::opaque::Encoder as OpaqueEncoder; use rbml::opaque::Decoder as OpaqueDecoder; use rustc::middle::cstore::tls; use rustc::middle::def_id::DefId; -use rustc::middle::ty::subst::Substs; -use rustc::middle::ty::{self, TyCtxt}; +use rustc::ty::subst::Substs; +use rustc::ty::{self, TyCtxt}; use decoder::{self, Cmd}; use encoder; diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs index 8c88a63a161..ed59fce77a0 100644 --- a/src/librustc_metadata/tydecode.rs +++ b/src/librustc_metadata/tydecode.rs @@ -20,9 +20,9 @@ use rustc_front::hir; use middle::def_id::{DefId, DefIndex}; use middle::region; -use middle::ty::subst; -use middle::ty::subst::VecPerParamSpace; -use middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::subst; +use rustc::ty::subst::VecPerParamSpace; +use rustc::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rbml; use rbml::leb128; diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index 6fc9b91213d..1d57918d173 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -19,10 +19,10 @@ use std::io::prelude::*; use middle::def_id::DefId; use middle::region; -use middle::ty::subst; -use middle::ty::subst::VecPerParamSpace; -use middle::ty::ParamTy; -use middle::ty::{self, Ty, TyCtxt}; +use rustc::ty::subst; +use rustc::ty::subst::VecPerParamSpace; +use rustc::ty::ParamTy; +use rustc::ty::{self, Ty, TyCtxt}; use rustc::util::nodemap::FnvHashMap; use rustc_front::hir; diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 30c039cdde0..231d7da10a0 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -15,7 +15,7 @@ use build::expr::category::{Category, RvalueFunc}; use build::scope::LoopScope; use hair::*; use rustc::middle::region::CodeExtent; -use rustc::middle::ty; +use rustc::ty; use rustc::mir::repr::*; use syntax::codemap::Span; diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index b1286e935b6..581e8e35ee8 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -16,7 +16,7 @@ use build::{BlockAnd, BlockAndExtension, Builder}; use rustc_data_structures::fnv::FnvHashMap; use rustc::middle::const_eval::ConstVal; -use rustc::middle::ty::{AdtDef, Ty}; +use rustc::ty::{AdtDef, Ty}; use rustc::mir::repr::*; use hair::*; use syntax::ast::{Name, NodeId}; diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 3211e5849a0..5a1c3739ef5 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -20,7 +20,7 @@ use build::matches::{Candidate, MatchPair, Test, TestKind}; use hair::*; use rustc_data_structures::fnv::FnvHashMap; use rustc::middle::const_eval::ConstVal; -use rustc::middle::ty::{self, Ty}; +use rustc::ty::{self, Ty}; use rustc::mir::repr::*; use syntax::codemap::Span; diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 0d169078330..86f15a63193 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -12,7 +12,7 @@ //! kind of thing. use build::Builder; -use rustc::middle::ty::Ty; +use rustc::ty::Ty; use rustc::mir::repr::*; use std::u32; use syntax::codemap::Span; diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index b79f492179f..82f7ddebf0b 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -10,7 +10,7 @@ use hair::cx::Cx; use rustc::middle::region::{CodeExtent, CodeExtentData}; -use rustc::middle::ty::{FnOutput, Ty}; +use rustc::ty::{FnOutput, Ty}; use rustc::mir::repr::*; use rustc_data_structures::fnv::FnvHashMap; use rustc_front::hir; diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 033e1361d4a..bac7b310dc7 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -89,8 +89,8 @@ should go to. use build::{BlockAnd, BlockAndExtension, Builder, CFG, ScopeAuxiliary}; use rustc::middle::region::{CodeExtent, CodeExtentData}; use rustc::middle::lang_items; -use rustc::middle::ty::subst::{Substs, Subst, VecPerParamSpace}; -use rustc::middle::ty::{self, Ty, TyCtxt}; +use rustc::ty::subst::{Substs, Subst, VecPerParamSpace}; +use rustc::ty::{self, Ty, TyCtxt}; use rustc::mir::repr::*; use syntax::codemap::{Span, DUMMY_SP}; use syntax::parse::token::intern_and_get_ident; diff --git a/src/librustc_mir/graphviz.rs b/src/librustc_mir/graphviz.rs index a5e749ea687..959b1fdef52 100644 --- a/src/librustc_mir/graphviz.rs +++ b/src/librustc_mir/graphviz.rs @@ -10,7 +10,7 @@ use dot; use rustc::mir::repr::*; -use rustc::middle::ty; +use rustc::ty; use std::fmt::Debug; use std::io::{self, Write}; use syntax::ast::NodeId; diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 4d87d926e40..aa55ee3e3f7 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -19,7 +19,7 @@ use rustc::middle::def::Def; use rustc::middle::const_eval::{self, ConstVal}; use rustc::middle::region::CodeExtent; use rustc::middle::pat_util; -use rustc::middle::ty::{self, VariantDef, Ty}; +use rustc::ty::{self, VariantDef, Ty}; use rustc::mir::repr::*; use rustc_front::hir; use rustc_front::util as hir_util; diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index d603979906d..30467a981d9 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -20,9 +20,9 @@ use rustc::mir::repr::*; use rustc::middle::const_eval::{self, ConstVal}; use rustc::middle::def_id::DefId; -use rustc::middle::infer::InferCtxt; -use rustc::middle::ty::subst::{Subst, Substs}; -use rustc::middle::ty::{self, Ty, TyCtxt}; +use rustc::infer::InferCtxt; +use rustc::ty::subst::{Subst, Substs}; +use rustc::ty::{self, Ty, TyCtxt}; use syntax::codemap::Span; use syntax::parse::token; use rustc_front::hir; diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs index a582a4622a6..0cb849555f2 100644 --- a/src/librustc_mir/hair/cx/pattern.rs +++ b/src/librustc_mir/hair/cx/pattern.rs @@ -14,7 +14,7 @@ use rustc_data_structures::fnv::FnvHashMap; use rustc::middle::const_eval; use rustc::middle::def::Def; use rustc::middle::pat_util::{pat_is_resolved_const, pat_is_binding}; -use rustc::middle::ty::{self, Ty}; +use rustc::ty::{self, Ty}; use rustc::mir::repr::*; use rustc_front::hir::{self, PatKind}; use syntax::ast; diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 3eca7f0a877..79c8356bb55 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -19,8 +19,8 @@ use rustc::mir::repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp, use rustc::middle::const_eval::ConstVal; use rustc::middle::def_id::DefId; use rustc::middle::region::CodeExtent; -use rustc::middle::ty::subst::Substs; -use rustc::middle::ty::{self, AdtDef, ClosureSubsts, Region, Ty}; +use rustc::ty::subst::Substs; +use rustc::ty::{self, AdtDef, ClosureSubsts, Region, Ty}; use rustc_front::hir; use syntax::ast; use syntax::codemap::Span; diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 5a6e2edfdf9..21cc8d35320 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -26,9 +26,9 @@ use pretty; use hair::cx::Cx; use rustc::mir::mir_map::MirMap; -use rustc::middle::infer; -use rustc::middle::traits::ProjectionMode; -use rustc::middle::ty::{self, Ty, TyCtxt}; +use rustc::infer; +use rustc::traits::ProjectionMode; +use rustc::ty::{self, Ty, TyCtxt}; use rustc::util::common::ErrorReported; use rustc::util::nodemap::NodeMap; use rustc_front::hir; diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs index 834897f8eae..2c50697c37f 100644 --- a/src/librustc_mir/pretty.rs +++ b/src/librustc_mir/pretty.rs @@ -10,7 +10,7 @@ use build::{Location, ScopeAuxiliaryVec}; use rustc::mir::repr::*; -use rustc::middle::ty::{self, TyCtxt}; +use rustc::ty::{self, TyCtxt}; use rustc_data_structures::fnv::FnvHashMap; use std::fmt::Display; use std::fs; diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index 6ea684c2f5c..12bfa3aebc2 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -12,8 +12,8 @@ //! We want to do this once just before trans, so trans does not have to take //! care erasing regions all over the place. -use rustc::middle::subst::Substs; -use rustc::middle::ty::{Ty, TyCtxt}; +use rustc::ty::subst::Substs; +use rustc::ty::{Ty, TyCtxt}; use rustc::mir::repr::*; use rustc::mir::visit::MutVisitor; use rustc::mir::transform::{MirPass, Pass}; diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs index 0e9a1810787..edfe75b8430 100644 --- a/src/librustc_mir/transform/no_landing_pads.rs +++ b/src/librustc_mir/transform/no_landing_pads.rs @@ -11,7 +11,7 @@ //! This pass removes the unwind branch of all the terminators when the no-landing-pads option is //! specified. -use rustc::middle::ty::TyCtxt; +use rustc::ty::TyCtxt; use rustc::mir::repr::*; use rustc::mir::visit::MutVisitor; use rustc::mir::transform::{Pass, MirPass}; diff --git a/src/librustc_mir/transform/remove_dead_blocks.rs b/src/librustc_mir/transform/remove_dead_blocks.rs index 4513aeef86d..dc1ddad124f 100644 --- a/src/librustc_mir/transform/remove_dead_blocks.rs +++ b/src/librustc_mir/transform/remove_dead_blocks.rs @@ -33,7 +33,7 @@ //! and does not renumber anything. use rustc_data_structures::bitvec::BitVector; -use rustc::middle::ty::TyCtxt; +use rustc::ty::TyCtxt; use rustc::mir::repr::*; use rustc::mir::transform::{Pass, MirPass}; use syntax::ast::NodeId; diff --git a/src/librustc_mir/transform/simplify_cfg.rs b/src/librustc_mir/transform/simplify_cfg.rs index 21b1d022fda..cbde292cb99 100644 --- a/src/librustc_mir/transform/simplify_cfg.rs +++ b/src/librustc_mir/transform/simplify_cfg.rs @@ -9,7 +9,7 @@ // except according to those terms. use rustc::middle::const_eval::ConstVal; -use rustc::middle::ty::TyCtxt; +use rustc::ty::TyCtxt; use rustc::mir::repr::*; use rustc::mir::transform::{MirPass, Pass}; use pretty; diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index c0605ebe6d4..6cfde27ac97 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -12,10 +12,10 @@ #![allow(unreachable_code)] use rustc::dep_graph::DepNode; -use rustc::middle::infer::{self, InferCtxt}; -use rustc::middle::traits::{self, ProjectionMode}; -use rustc::middle::ty::fold::TypeFoldable; -use rustc::middle::ty::{self, Ty, TyCtxt}; +use rustc::infer::{self, InferCtxt}; +use rustc::traits::{self, ProjectionMode}; +use rustc::ty::fold::TypeFoldable; +use rustc::ty::{self, Ty, TyCtxt}; use rustc::mir::repr::*; use rustc::mir::tcx::LvalueTy; use rustc::mir::transform::{MirPass, Pass}; diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index c2b76459418..571d5bd9bc5 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -25,18 +25,18 @@ // by borrowck::gather_loans use rustc::dep_graph::DepNode; -use rustc::middle::ty::cast::{CastKind}; +use rustc::ty::cast::{CastKind}; use rustc::middle::const_eval::{self, ConstEvalErr}; use rustc::middle::const_eval::ErrKind::IndexOpFeatureGated; use rustc::middle::const_eval::EvalHint::ExprTypeChecked; use rustc::middle::def::Def; use rustc::middle::def_id::DefId; use rustc::middle::expr_use_visitor as euv; -use rustc::middle::infer; +use rustc::infer; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; -use rustc::middle::ty::{self, Ty, TyCtxt}; -use rustc::middle::traits::{self, ProjectionMode}; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::traits::{self, ProjectionMode}; use rustc::util::nodemap::NodeMap; use rustc::middle::const_qualif::ConstQualif; use rustc::lint::builtin::CONST_ERR; diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs index 88048b514e1..98502f5a16e 100644 --- a/src/librustc_passes/rvalues.rs +++ b/src/librustc_passes/rvalues.rs @@ -13,10 +13,10 @@ use rustc::dep_graph::DepNode; use rustc::middle::expr_use_visitor as euv; -use rustc::middle::infer; +use rustc::infer; use rustc::middle::mem_categorization as mc; -use rustc::middle::ty::{self, TyCtxt, ParameterEnvironment}; -use rustc::middle::traits::ProjectionMode; +use rustc::ty::{self, TyCtxt, ParameterEnvironment}; +use rustc::traits::ProjectionMode; use rustc_front::hir; use rustc_front::intravisit; diff --git a/src/librustc_platform_intrinsics/aarch64.rs b/src/librustc_platform_intrinsics/aarch64.rs index 59986a905a2..97fe632a529 100644 --- a/src/librustc_platform_intrinsics/aarch64.rs +++ b/src/librustc_platform_intrinsics/aarch64.rs @@ -15,7 +15,7 @@ use {Intrinsic, Type}; use IntrinsicDef::Named; -use rustc::middle::ty::TyCtxt; +use rustc::ty::TyCtxt; // The default inlining settings trigger a pathological behaviour in // LLVM, which causes makes compilation very slow. See #28273. diff --git a/src/librustc_platform_intrinsics/arm.rs b/src/librustc_platform_intrinsics/arm.rs index d71f59e8e68..65751d65232 100644 --- a/src/librustc_platform_intrinsics/arm.rs +++ b/src/librustc_platform_intrinsics/arm.rs @@ -15,7 +15,7 @@ use {Intrinsic, Type}; use IntrinsicDef::Named; -use rustc::middle::ty::TyCtxt; +use rustc::ty::TyCtxt; // The default inlining settings trigger a pathological behaviour in // LLVM, which causes makes compilation very slow. See #28273. diff --git a/src/librustc_platform_intrinsics/lib.rs b/src/librustc_platform_intrinsics/lib.rs index 53976308bdc..9736d558769 100644 --- a/src/librustc_platform_intrinsics/lib.rs +++ b/src/librustc_platform_intrinsics/lib.rs @@ -19,7 +19,7 @@ extern crate rustc_llvm as llvm; extern crate rustc; -use rustc::middle::ty::TyCtxt; +use rustc::ty::TyCtxt; pub struct Intrinsic { pub inputs: &'static [&'static Type], diff --git a/src/librustc_platform_intrinsics/x86.rs b/src/librustc_platform_intrinsics/x86.rs index eccdc77f33c..de9d3dcf355 100644 --- a/src/librustc_platform_intrinsics/x86.rs +++ b/src/librustc_platform_intrinsics/x86.rs @@ -15,7 +15,7 @@ use {Intrinsic, Type}; use IntrinsicDef::Named; -use rustc::middle::ty::TyCtxt; +use rustc::ty::TyCtxt; // The default inlining settings trigger a pathological behaviour in // LLVM, which causes makes compilation very slow. See #28273. diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 79ccc8fb2b2..304932df412 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -42,7 +42,7 @@ use rustc::middle::cstore::CrateStore; use rustc::middle::def::{self, Def}; use rustc::middle::def_id::DefId; use rustc::middle::privacy::{AccessLevel, AccessLevels}; -use rustc::middle::ty::{self, TyCtxt}; +use rustc::ty::{self, TyCtxt}; use rustc::util::nodemap::{NodeMap, NodeSet}; use rustc::front::map as ast_map; diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index fac79eb8a28..211bff352fe 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -26,7 +26,7 @@ use {resolve_error, resolve_struct_error, ResolutionError}; use rustc::middle::cstore::{CrateStore, ChildItem, DlDef}; use rustc::middle::def::*; use rustc::middle::def_id::{CRATE_DEF_INDEX, DefId}; -use rustc::middle::ty::VariantKind; +use rustc::ty::VariantKind; use syntax::ast::{Name, NodeId}; use syntax::attr::AttrMetaMethods; diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index fb0f0125812..2f6d5e1c36e 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -55,8 +55,8 @@ use rustc::middle::cstore::CrateStore; use rustc::middle::def::*; use rustc::middle::def_id::DefId; use rustc::middle::pat_util::pat_bindings; -use rustc::middle::ty::subst::{ParamSpace, FnSpace, TypeSpace}; -use rustc::middle::ty::{Freevar, FreevarMap, TraitMap, GlobMap}; +use rustc::ty::subst::{ParamSpace, FnSpace, TypeSpace}; +use rustc::ty::{Freevar, FreevarMap, TraitMap, GlobMap}; use rustc::util::nodemap::{NodeMap, FnvHashMap}; use syntax::ast::{self, FloatTy}; diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 5d578011da8..f11be65521b 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -102,8 +102,8 @@ use util::sha2::{Digest, Sha256}; use rustc::middle::cstore; use rustc::middle::def_id::DefId; -use rustc::middle::ty::{self, TypeFoldable}; -use rustc::middle::ty::item_path::{ItemPathBuffer, RootMode}; +use rustc::ty::{self, TypeFoldable}; +use rustc::ty::item_path::{ItemPathBuffer, RootMode}; use rustc::front::map::definitions::{DefPath, DefPathData}; use std::fmt::Write; diff --git a/src/librustc_trans/save/data.rs b/src/librustc_trans/save/data.rs index 3eaaa3fc493..b9d9d58b5bd 100644 --- a/src/librustc_trans/save/data.rs +++ b/src/librustc_trans/save/data.rs @@ -16,7 +16,7 @@ use std::hash::Hasher; use middle::def_id::DefId; -use middle::ty; +use rustc::ty; use syntax::ast::{CrateNum, NodeId}; use syntax::codemap::Span; diff --git a/src/librustc_trans/save/dump_visitor.rs b/src/librustc_trans/save/dump_visitor.rs index 65f48d1ff5e..9d465d87047 100644 --- a/src/librustc_trans/save/dump_visitor.rs +++ b/src/librustc_trans/save/dump_visitor.rs @@ -31,7 +31,7 @@ use session::Session; use middle::def::Def; use middle::def_id::DefId; -use middle::ty::{self, TyCtxt}; +use rustc::ty::{self, TyCtxt}; use std::collections::HashSet; use std::hash::*; diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 4bbb7624693..c07733b218a 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::ty::{self, TyCtxt}; +use rustc::ty::{self, TyCtxt}; use middle::def::Def; use middle::def_id::DefId; diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 561fd022ece..7794ac763c6 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -195,12 +195,12 @@ use middle::const_eval; use middle::def::{Def, DefMap}; use middle::def_id::DefId; use middle::expr_use_visitor as euv; -use middle::infer; +use rustc::infer; use middle::lang_items::StrEqFnLangItem; use middle::mem_categorization as mc; use middle::mem_categorization::Categorization; use middle::pat_util::*; -use middle::ty::subst::Substs; +use rustc::ty::subst::Substs; use trans::adt; use trans::base::*; use trans::build::{AddCase, And, Br, CondBr, GEPi, InBoundsGEP, Load, PointerCast}; @@ -218,8 +218,8 @@ use trans::tvec; use trans::type_of; use trans::Disr; use trans::value::Value; -use middle::ty::{self, Ty, TyCtxt}; -use middle::traits::ProjectionMode; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::traits::ProjectionMode; use session::config::NoDebugInfo; use util::common::indenter; use util::nodemap::FnvHashMap; diff --git a/src/librustc_trans/trans/abi.rs b/src/librustc_trans/trans/abi.rs index fd086522b2e..87253924172 100644 --- a/src/librustc_trans/trans/abi.rs +++ b/src/librustc_trans/trans/abi.rs @@ -27,7 +27,7 @@ use trans::type_::Type; use trans::type_of; use rustc_front::hir; -use middle::ty::{self, Ty}; +use rustc::ty::{self, Ty}; use libc::c_uint; @@ -318,7 +318,7 @@ impl FnType { } ty::TyRef(b, mt) => { - use middle::ty::{BrAnon, ReLateBound}; + use rustc::ty::{BrAnon, ReLateBound}; // `&mut` pointer parameters never alias other parameters, or mutable global data // diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index e94c4ebe3b5..f14c1a573cc 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -48,8 +48,8 @@ use std; use std::rc::Rc; use llvm::{ValueRef, True, IntEQ, IntNE}; -use middle::ty::subst; -use middle::ty::{self, Ty, TyCtxt}; +use rustc::ty::subst; +use rustc::ty::{self, Ty, TyCtxt}; use syntax::ast; use syntax::attr; use syntax::attr::IntType; diff --git a/src/librustc_trans/trans/assert_dep_graph.rs b/src/librustc_trans/trans/assert_dep_graph.rs index 11386715492..dcf23039e25 100644 --- a/src/librustc_trans/trans/assert_dep_graph.rs +++ b/src/librustc_trans/trans/assert_dep_graph.rs @@ -40,7 +40,7 @@ use graphviz as dot; use rustc::dep_graph::{DepGraphQuery, DepNode}; use rustc::middle::def_id::DefId; -use rustc::middle::ty::TyCtxt; +use rustc::ty::TyCtxt; use rustc_data_structures::fnv::{FnvHashMap, FnvHashSet}; use rustc_data_structures::graph::{Direction, INCOMING, OUTGOING, NodeIndex}; use rustc_front::hir; diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 5d7da08cf9f..d4add752fa4 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -34,17 +34,17 @@ use back::{link, symbol_names}; use lint; use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param}; use llvm; -use middle::cfg; +use rustc::cfg; use middle::cstore::CrateStore; use middle::def_id::DefId; -use middle::infer; +use rustc::infer; use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem}; use middle::weak_lang_items; use middle::pat_util::simple_name; -use middle::ty::subst::{self, Substs}; -use middle::traits; -use middle::ty::{self, Ty, TyCtxt, TypeFoldable}; -use middle::ty::adjustment::CustomCoerceUnsized; +use rustc::ty::subst::{self, Substs}; +use rustc::traits; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::adjustment::CustomCoerceUnsized; use rustc::dep_graph::DepNode; use rustc::front::map as hir_map; use rustc::util::common::time; diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index baad981a8c8..8559db3ce5e 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -22,10 +22,10 @@ use back::symbol_names; use llvm::{self, ValueRef, get_params}; use middle::cstore::LOCAL_CRATE; use middle::def_id::DefId; -use middle::infer; -use middle::ty::subst; -use middle::ty::subst::{Substs}; -use middle::traits; +use rustc::infer; +use rustc::ty::subst; +use rustc::ty::subst::{Substs}; +use rustc::traits; use rustc::front::map as hir_map; use trans::abi::{Abi, FnType}; use trans::adt; @@ -53,7 +53,7 @@ use trans::type_::Type; use trans::type_of; use trans::value::Value; use trans::Disr; -use middle::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_front::hir; use syntax::codemap::DUMMY_SP; diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index bd2d05915f6..78481e0ed92 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -130,7 +130,7 @@ use trans::glue; use middle::region; use trans::type_::Type; use trans::value::Value; -use middle::ty::{Ty, TyCtxt}; +use rustc::ty::{Ty, TyCtxt}; use std::fmt; use syntax::ast; diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index ff3235385a9..3040d6a37c1 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -12,8 +12,8 @@ use arena::TypedArena; use back::symbol_names; use llvm::{ValueRef, get_param, get_params}; use middle::def_id::DefId; -use middle::infer; -use middle::traits::ProjectionMode; +use rustc::infer; +use rustc::traits::ProjectionMode; use trans::abi::{Abi, FnType}; use trans::adt; use trans::attributes; @@ -30,7 +30,7 @@ use trans::expr; use trans::monomorphize::{Instance}; use trans::value::Value; use trans::Disr; -use middle::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, Ty, TyCtxt}; use session::config::FullDebugInfo; use syntax::ast; diff --git a/src/librustc_trans/trans/collector.rs b/src/librustc_trans/trans/collector.rs index 41bd7497433..5c36f9bb68c 100644 --- a/src/librustc_trans/trans/collector.rs +++ b/src/librustc_trans/trans/collector.rs @@ -194,10 +194,10 @@ use rustc_front::intravisit as hir_visit; use rustc::front::map as hir_map; use rustc::middle::def_id::DefId; use rustc::middle::lang_items::{ExchangeFreeFnLangItem, ExchangeMallocFnLangItem}; -use rustc::middle::traits; -use rustc::middle::ty::subst::{self, Substs, Subst}; -use rustc::middle::ty::{self, Ty, TypeFoldable}; -use rustc::middle::ty::adjustment::CustomCoerceUnsized; +use rustc::traits; +use rustc::ty::subst::{self, Substs, Subst}; +use rustc::ty::{self, Ty, TypeFoldable}; +use rustc::ty::adjustment::CustomCoerceUnsized; use rustc::mir::repr as mir; use rustc::mir::visit as mir_visit; use rustc::mir::visit::Visitor as MirVisitor; @@ -580,7 +580,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, }; if let Some(destructor_did) = destructor_did { - use rustc::middle::ty::ToPolyTraitRef; + use rustc::ty::ToPolyTraitRef; let drop_trait_def_id = ccx.tcx() .lang_items diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index eb443a3b0b9..a6953f262c8 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -16,12 +16,12 @@ use session::Session; use llvm; use llvm::{ValueRef, BasicBlockRef, BuilderRef, ContextRef, TypeKind}; use llvm::{True, False, Bool, OperandBundleDef}; -use middle::cfg; +use rustc::cfg; use middle::def::Def; use middle::def_id::DefId; -use middle::infer; +use rustc::infer; use middle::lang_items::LangItem; -use middle::ty::subst::Substs; +use rustc::ty::subst::Substs; use trans::abi::{Abi, FnType}; use trans::base; use trans::build; @@ -37,9 +37,9 @@ use trans::mir::CachedMir; use trans::monomorphize; use trans::type_::Type; use trans::value::Value; -use middle::ty::{self, Ty, TyCtxt}; -use middle::traits::{self, SelectionContext, ProjectionMode}; -use middle::ty::fold::{TypeFolder, TypeFoldable}; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::traits::{self, SelectionContext, ProjectionMode}; +use rustc::ty::fold::{TypeFolder, TypeFoldable}; use rustc_front::hir; use util::nodemap::NodeMap; diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 956c40a443f..7b832a7e99a 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -32,11 +32,11 @@ use trans::type_::Type; use trans::type_of; use trans::value::Value; use trans::Disr; -use middle::ty::subst::Substs; -use middle::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer}; -use middle::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer}; -use middle::ty::{self, Ty, TyCtxt}; -use middle::ty::cast::{CastTy,IntTy}; +use rustc::ty::subst::Substs; +use rustc::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer}; +use rustc::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer}; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::cast::{CastTy,IntTy}; use util::nodemap::NodeMap; use rustc_const_eval::{ConstInt, ConstMathErr, ConstUsize, ConstIsize}; diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index f2ea8ad8612..4511989534d 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -14,7 +14,7 @@ use rustc::dep_graph::{DepNode, DepTrackingMap, DepTrackingMapConfig}; use middle::cstore::LinkMeta; use middle::def::ExportMap; use middle::def_id::DefId; -use middle::traits; +use rustc::traits; use rustc::mir::mir_map::MirMap; use rustc::mir::repr as mir; use trans::adt; @@ -29,8 +29,8 @@ use trans::Instance; use trans::collector::{TransItem, TransItemState}; use trans::type_::{Type, TypeNames}; -use middle::ty::subst::{Substs, VecPerParamSpace}; -use middle::ty::{self, Ty, TyCtxt}; +use rustc::ty::subst::{Substs, VecPerParamSpace}; +use rustc::ty::{self, Ty, TyCtxt}; use session::config::NoDebugInfo; use session::Session; use util::sha2::Sha256; diff --git a/src/librustc_trans/trans/controlflow.rs b/src/librustc_trans/trans/controlflow.rs index 65f5ab1f228..80ff11e968a 100644 --- a/src/librustc_trans/trans/controlflow.rs +++ b/src/librustc_trans/trans/controlflow.rs @@ -11,7 +11,7 @@ use llvm::ValueRef; use middle::def::Def; use middle::lang_items::{PanicFnLangItem, PanicBoundsCheckFnLangItem}; -use middle::ty::subst::Substs; +use rustc::ty::subst::Substs; use trans::base::*; use trans::basic_block::BasicBlock; use trans::build::*; diff --git a/src/librustc_trans/trans/datum.rs b/src/librustc_trans/trans/datum.rs index 649f6180de2..c0858a6d93b 100644 --- a/src/librustc_trans/trans/datum.rs +++ b/src/librustc_trans/trans/datum.rs @@ -102,7 +102,7 @@ use trans::cleanup::{CleanupMethods, DropHintDatum, DropHintMethods}; use trans::expr; use trans::tvec; use trans::value::Value; -use middle::ty::Ty; +use rustc::ty::Ty; use std::fmt; use syntax::ast; diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index a654a3f37c8..bd2a8e0193d 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -24,16 +24,16 @@ use llvm::{self, ValueRef}; use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor, DICompositeType}; use middle::def_id::DefId; -use middle::infer; +use rustc::infer; use middle::pat_util; -use middle::ty::subst; +use rustc::ty::subst; use rustc::front::map as hir_map; use rustc_front::hir::{self, PatKind}; use trans::{type_of, adt, machine, monomorphize}; use trans::common::{self, CrateContext, FunctionContext, Block}; use trans::_match::{BindingInfo, TransBindingMode}; use trans::type_::Type; -use middle::ty::{self, Ty}; +use rustc::ty::{self, Ty}; use session::config::{self, FullDebugInfo}; use util::nodemap::FnvHashMap; use util::common::path2cstr; diff --git a/src/librustc_trans/trans/debuginfo/mod.rs b/src/librustc_trans/trans/debuginfo/mod.rs index dbba03cf455..198a9899fda 100644 --- a/src/librustc_trans/trans/debuginfo/mod.rs +++ b/src/librustc_trans/trans/debuginfo/mod.rs @@ -27,8 +27,8 @@ use llvm::{ModuleRef, ContextRef, ValueRef}; use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray, DIDescriptor, FlagPrototyped}; use middle::def_id::DefId; -use middle::infer::normalize_associated_type; -use middle::ty::subst::{self, Substs}; +use rustc::infer::normalize_associated_type; +use rustc::ty::subst::{self, Substs}; use rustc_front; use rustc_front::hir; @@ -36,8 +36,8 @@ use trans::abi::Abi; use trans::common::{NodeIdAndSpan, CrateContext, FunctionContext, Block}; use trans; use trans::monomorphize; -use middle::infer; -use middle::ty::{self, Ty}; +use rustc::infer; +use rustc::ty::{self, Ty}; use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo}; use util::nodemap::{NodeMap, FnvHashMap, FnvHashSet}; use rustc::front::map as hir_map; diff --git a/src/librustc_trans/trans/debuginfo/type_names.rs b/src/librustc_trans/trans/debuginfo/type_names.rs index a051966795d..fc9ace89ab7 100644 --- a/src/librustc_trans/trans/debuginfo/type_names.rs +++ b/src/librustc_trans/trans/debuginfo/type_names.rs @@ -14,9 +14,9 @@ use super::namespace::crate_root_namespace; use trans::common::CrateContext; use middle::def_id::DefId; -use middle::infer; -use middle::ty::subst; -use middle::ty::{self, Ty}; +use rustc::infer; +use rustc::ty::subst; +use rustc::ty::{self, Ty}; use rustc_front::hir; diff --git a/src/librustc_trans/trans/declare.rs b/src/librustc_trans/trans/declare.rs index e63f17770bc..41a87f8d6de 100644 --- a/src/librustc_trans/trans/declare.rs +++ b/src/librustc_trans/trans/declare.rs @@ -20,8 +20,8 @@ //! * Use define_* family of methods when you might be defining the ValueRef. //! * When in doubt, define. use llvm::{self, ValueRef}; -use middle::ty; -use middle::infer; +use rustc::ty; +use rustc::infer; use trans::abi::{Abi, FnType}; use trans::attributes; use trans::context::CrateContext; diff --git a/src/librustc_trans/trans/disr.rs b/src/librustc_trans/trans/disr.rs index d74c1ac50ad..fc79fa813aa 100644 --- a/src/librustc_trans/trans/disr.rs +++ b/src/librustc_trans/trans/disr.rs @@ -24,8 +24,8 @@ impl ::std::ops::BitAnd for Disr { } } -impl From<::middle::ty::Disr> for Disr { - fn from(i: ::middle::ty::Disr) -> Disr { +impl From<::rustc::ty::Disr> for Disr { + fn from(i: ::rustc::ty::Disr) -> Disr { Disr(i.to_u64_unchecked()) } } diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 8b7527fd7de..8f9f44fb2dd 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -54,7 +54,7 @@ use self::lazy_binop_ty::*; use llvm::{self, ValueRef, TypeKind}; use middle::const_qualif::ConstQualif; use middle::def::Def; -use middle::ty::subst::Substs; +use rustc::ty::subst::Substs; use trans::{_match, abi, adt, asm, base, closure, consts, controlflow}; use trans::base::*; use trans::build::*; @@ -70,12 +70,12 @@ use trans::tvec; use trans::type_of; use trans::value::Value; use trans::Disr; -use middle::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer}; -use middle::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer}; -use middle::ty::adjustment::CustomCoerceUnsized; -use middle::ty::{self, Ty, TyCtxt}; -use middle::ty::MethodCall; -use middle::ty::cast::{CastKind, CastTy}; +use rustc::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer}; +use rustc::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer}; +use rustc::ty::adjustment::CustomCoerceUnsized; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::MethodCall; +use rustc::ty::cast::{CastKind, CastTy}; use util::common::indenter; use trans::machine::{llsize_of, llsize_of_alloc}; use trans::type_::Type; @@ -1859,8 +1859,8 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, id: ast::NodeId) -> DatumBlock<'blk, 'tcx, Expr> { - use middle::ty::cast::CastTy::*; - use middle::ty::cast::IntTy::*; + use rustc::ty::cast::CastTy::*; + use rustc::ty::cast::IntTy::*; fn int_cast(bcx: Block, lldsttype: Type, @@ -2194,7 +2194,7 @@ impl OverflowOpViaIntrinsic { fn to_intrinsic_name(&self, tcx: &TyCtxt, ty: Ty) -> &'static str { use syntax::ast::IntTy::*; use syntax::ast::UintTy::*; - use middle::ty::{TyInt, TyUint}; + use rustc::ty::{TyInt, TyUint}; let new_sty = match ty.sty { TyInt(Is) => match &tcx.sess.target.target.target_pointer_width[..] { diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index 972e32a2674..dc4fc5a9ccf 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -18,9 +18,9 @@ use back::symbol_names; use llvm; use llvm::{ValueRef, get_param}; use middle::lang_items::ExchangeFreeFnLangItem; -use middle::ty::subst::{Substs}; -use middle::traits; -use middle::ty::{self, Ty, TyCtxt}; +use rustc::ty::subst::{Substs}; +use rustc::traits; +use rustc::ty::{self, Ty, TyCtxt}; use trans::abi::{Abi, FnType}; use trans::adt; use trans::adt::GetDtorType; // for tcx.dtor_type() diff --git a/src/librustc_trans/trans/inline.rs b/src/librustc_trans/trans/inline.rs index 3e37b7007c3..b8abc1b6107 100644 --- a/src/librustc_trans/trans/inline.rs +++ b/src/librustc_trans/trans/inline.rs @@ -11,7 +11,7 @@ use llvm::{AvailableExternallyLinkage, InternalLinkage, SetLinkage}; use middle::cstore::{CrateStore, FoundAst, InlinedItem}; use middle::def_id::DefId; -use middle::ty::subst::Substs; +use rustc::ty::subst::Substs; use trans::base::{push_ctxt, trans_item, trans_fn}; use trans::callee::Callee; use trans::common::*; diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index d3b84fbac1a..9577a1817d7 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -15,9 +15,9 @@ use intrinsics::{self, Intrinsic}; use libc; use llvm; use llvm::{ValueRef, TypeKind}; -use middle::infer; -use middle::ty::subst; -use middle::ty::subst::FnSpace; +use rustc::infer; +use rustc::ty::subst; +use rustc::ty::subst::FnSpace; use trans::abi::{Abi, FnType}; use trans::adt; use trans::attributes; @@ -36,9 +36,9 @@ use trans::glue; use trans::type_of; use trans::machine; use trans::type_::Type; -use middle::ty::{self, Ty, TypeFoldable}; +use rustc::ty::{self, Ty, TypeFoldable}; use trans::Disr; -use middle::ty::subst::Substs; +use rustc::ty::subst::Substs; use rustc::dep_graph::DepNode; use rustc_front::hir; use syntax::ast; @@ -1694,7 +1694,7 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> // Returns None if the type is not an integer fn int_type_width_signed<'tcx>(sty: &ty::TypeVariants<'tcx>, ccx: &CrateContext) -> Option<(u64, bool)> { - use rustc::middle::ty::{TyInt, TyUint}; + use rustc::ty::{TyInt, TyUint}; match *sty { TyInt(t) => Some((match t { ast::IntTy::Is => { @@ -1730,7 +1730,7 @@ fn int_type_width_signed<'tcx>(sty: &ty::TypeVariants<'tcx>, ccx: &CrateContext) // Returns None if the type is not a float fn float_type_width<'tcx>(sty: &ty::TypeVariants<'tcx>) -> Option { - use rustc::middle::ty::TyFloat; + use rustc::ty::TyFloat; match *sty { TyFloat(t) => Some(match t { ast::FloatTy::F32 => 32, diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index f08ee4d48dc..696a0e3c0b6 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -14,10 +14,10 @@ use arena::TypedArena; use back::symbol_names; use llvm::{ValueRef, get_params}; use middle::def_id::DefId; -use middle::infer; -use middle::ty::subst::{FnSpace, Subst, Substs}; -use middle::ty::subst; -use middle::traits::{self, ProjectionMode}; +use rustc::infer; +use rustc::ty::subst::{FnSpace, Subst, Substs}; +use rustc::ty::subst; +use rustc::traits::{self, ProjectionMode}; use trans::abi::FnType; use trans::base::*; use trans::build::*; @@ -33,7 +33,7 @@ use trans::machine; use trans::type_::Type; use trans::type_of::*; use trans::value::Value; -use middle::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use syntax::ast::Name; use syntax::codemap::DUMMY_SP; diff --git a/src/librustc_trans/trans/mir/block.rs b/src/librustc_trans/trans/mir/block.rs index 7abaeb44c1c..4f76fd56684 100644 --- a/src/librustc_trans/trans/mir/block.rs +++ b/src/librustc_trans/trans/mir/block.rs @@ -9,7 +9,7 @@ // except according to those terms. use llvm::{self, BasicBlockRef, ValueRef, OperandBundleDef}; -use rustc::middle::ty; +use rustc::ty; use rustc::mir::repr as mir; use trans::abi::{Abi, FnType}; use trans::adt; diff --git a/src/librustc_trans/trans/mir/constant.rs b/src/librustc_trans/trans/mir/constant.rs index d4934718d75..1e5c1c2c55a 100644 --- a/src/librustc_trans/trans/mir/constant.rs +++ b/src/librustc_trans/trans/mir/constant.rs @@ -9,7 +9,7 @@ // except according to those terms. use llvm::ValueRef; -use middle::ty::{Ty, TypeFoldable}; +use rustc::ty::{Ty, TypeFoldable}; use rustc::middle::const_eval::{self, ConstVal}; use rustc_const_eval::ConstInt::*; use rustc::mir::repr as mir; diff --git a/src/librustc_trans/trans/mir/drop.rs b/src/librustc_trans/trans/mir/drop.rs index 2e13abec5e3..cc033084ace 100644 --- a/src/librustc_trans/trans/mir/drop.rs +++ b/src/librustc_trans/trans/mir/drop.rs @@ -9,7 +9,7 @@ // except according to those terms. use llvm::ValueRef; -use rustc::middle::ty::Ty; +use rustc::ty::Ty; use trans::adt; use trans::base; use trans::common::{self, BlockAndBuilder}; diff --git a/src/librustc_trans/trans/mir/lvalue.rs b/src/librustc_trans/trans/mir/lvalue.rs index ffc3b120674..6271ad8d8b8 100644 --- a/src/librustc_trans/trans/mir/lvalue.rs +++ b/src/librustc_trans/trans/mir/lvalue.rs @@ -9,7 +9,7 @@ // except according to those terms. use llvm::ValueRef; -use rustc::middle::ty::{self, Ty, TypeFoldable}; +use rustc::ty::{self, Ty, TypeFoldable}; use rustc::mir::repr as mir; use rustc::mir::tcx::LvalueTy; use trans::abi; diff --git a/src/librustc_trans/trans/mir/mod.rs b/src/librustc_trans/trans/mir/mod.rs index 9df2cb712b1..ed4aa5fe583 100644 --- a/src/librustc_trans/trans/mir/mod.rs +++ b/src/librustc_trans/trans/mir/mod.rs @@ -10,7 +10,7 @@ use libc::c_uint; use llvm::{self, ValueRef}; -use middle::ty; +use rustc::ty; use rustc::mir::repr as mir; use rustc::mir::tcx::LvalueTy; use trans::base; diff --git a/src/librustc_trans/trans/mir/operand.rs b/src/librustc_trans/trans/mir/operand.rs index 6df4502fbc8..cc1446033de 100644 --- a/src/librustc_trans/trans/mir/operand.rs +++ b/src/librustc_trans/trans/mir/operand.rs @@ -9,7 +9,7 @@ // except according to those terms. use llvm::ValueRef; -use rustc::middle::ty::Ty; +use rustc::ty::Ty; use rustc::mir::repr as mir; use trans::base; use trans::common::{self, Block, BlockAndBuilder}; diff --git a/src/librustc_trans/trans/mir/rvalue.rs b/src/librustc_trans/trans/mir/rvalue.rs index 17c8aef244b..a78d0da5be4 100644 --- a/src/librustc_trans/trans/mir/rvalue.rs +++ b/src/librustc_trans/trans/mir/rvalue.rs @@ -9,8 +9,8 @@ // except according to those terms. use llvm::ValueRef; -use rustc::middle::ty::{self, Ty}; -use middle::ty::cast::{CastTy, IntTy}; +use rustc::ty::{self, Ty}; +use rustc::ty::cast::{CastTy, IntTy}; use middle::const_eval::ConstVal; use rustc_const_eval::ConstInt; use rustc::mir::repr as mir; diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 9a1b2790d32..0440c74a60a 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -12,11 +12,10 @@ use back::symbol_names; use llvm::ValueRef; use llvm; use middle::def_id::DefId; -use middle::infer::normalize_associated_type; -use middle::ty::subst; -use middle::ty::subst::{Subst, Substs}; -use middle::ty::{self, Ty, TyCtxt}; -use middle::ty::fold::{TypeFolder, TypeFoldable}; +use rustc::infer::normalize_associated_type; +use rustc::ty::subst; +use rustc::ty::subst::{Subst, Substs}; +use rustc::ty::{self, Ty, TypeFoldable, TyCtxt}; use trans::attributes; use trans::base::{push_ctxt}; use trans::base::trans_fn; diff --git a/src/librustc_trans/trans/symbol_names_test.rs b/src/librustc_trans/trans/symbol_names_test.rs index 63abbfd53b6..bcfab663966 100644 --- a/src/librustc_trans/trans/symbol_names_test.rs +++ b/src/librustc_trans/trans/symbol_names_test.rs @@ -15,7 +15,7 @@ //! paths etc in all kinds of annoying scenarios. use back::symbol_names; -use rustc::middle::ty::TyCtxt; +use rustc::ty::TyCtxt; use rustc_front::hir; use rustc_front::intravisit::{self, Visitor}; use syntax::ast; diff --git a/src/librustc_trans/trans/tvec.rs b/src/librustc_trans/trans/tvec.rs index 7a0ca86f5a2..4a7404b1fba 100644 --- a/src/librustc_trans/trans/tvec.rs +++ b/src/librustc_trans/trans/tvec.rs @@ -27,7 +27,7 @@ use trans::machine::llsize_of_alloc; use trans::type_::Type; use trans::type_of; use trans::value::Value; -use middle::ty::{self, Ty}; +use rustc::ty::{self, Ty}; use rustc_front::hir; diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index e81039908c1..00f42a3b243 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -11,13 +11,13 @@ #![allow(non_camel_case_types)] use middle::def_id::DefId; -use middle::infer; -use middle::ty::subst; +use rustc::infer; +use rustc::ty::subst; use trans::abi::FnType; use trans::adt; use trans::common::*; use trans::machine; -use middle::ty::{self, Ty, TypeFoldable}; +use rustc::ty::{self, Ty, TypeFoldable}; use trans::type_::Type; @@ -145,7 +145,7 @@ pub fn immediate_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> } } -/// Get the LLVM type corresponding to a Rust type, i.e. `middle::ty::Ty`. +/// Get the LLVM type corresponding to a Rust type, i.e. `rustc::ty::Ty`. /// This is the right LLVM type for an alloca containing a value of that type, /// and the pointee of an Lvalue Datum (which is always a LLVM pointer). /// For unsized types, the returned type is a fat pointer, thus the resulting @@ -163,7 +163,7 @@ pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type { in_memory_type_of(cx, ty) } -/// Get the LLVM type corresponding to a Rust type, i.e. `middle::ty::Ty`. +/// Get the LLVM type corresponding to a Rust type, i.e. `rustc::ty::Ty`. /// This is the right LLVM type for a field/array element of that type, /// and is the same as `type_of` for all Sized types. /// Unsized types, however, are represented by a "minimal unit", e.g. diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 3b3d2cbad10..af40b845767 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -54,10 +54,10 @@ use middle::const_eval::EvalHint::UncheckedExprHint; use middle::def::{self, Def}; use middle::def_id::DefId; use middle::resolve_lifetime as rl; -use middle::ty::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs, ParamSpace}; -use middle::traits; -use middle::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable}; -use middle::ty::wf::object_region_bounds; +use rustc::ty::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs, ParamSpace}; +use rustc::traits; +use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable}; +use rustc::ty::wf::object_region_bounds; use require_c_abi_if_variadic; use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope, diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 947488bde71..f8fa9c8e9b6 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -9,11 +9,11 @@ // except according to those terms. use middle::def::{self, Def}; -use middle::infer::{self, TypeOrigin}; +use rustc::infer::{self, TypeOrigin}; use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding}; use middle::pat_util::pat_is_resolved_const; -use middle::ty::subst::Substs; -use middle::ty::{self, Ty, TypeFoldable, LvaluePreference}; +use rustc::ty::subst::Substs; +use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference}; use check::{check_expr, check_expr_has_type, check_expr_with_expectation}; use check::{demand, FnCtxt, Expectation}; use check::{check_expr_with_lvalue_pref}; diff --git a/src/librustc_typeck/check/assoc.rs b/src/librustc_typeck/check/assoc.rs index 91916efa882..f7726bc9cf4 100644 --- a/src/librustc_typeck/check/assoc.rs +++ b/src/librustc_typeck/check/assoc.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::infer::InferCtxt; -use middle::traits::{self, FulfillmentContext, Normalized, MiscObligation, +use rustc::infer::InferCtxt; +use rustc::traits::{self, FulfillmentContext, Normalized, MiscObligation, SelectionContext, ObligationCause}; -use middle::ty::fold::TypeFoldable; +use rustc::ty::fold::TypeFoldable; use syntax::ast; use syntax::codemap::Span; diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index bf60f435a22..4e582033c8b 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -28,8 +28,8 @@ use CrateCtxt; use middle::cstore::LOCAL_CRATE; use middle::def::Def; use middle::def_id::DefId; -use middle::infer; -use middle::ty::{self, LvaluePreference, Ty}; +use rustc::infer; +use rustc::ty::{self, LvaluePreference, Ty}; use syntax::codemap::Span; use syntax::parse::token; use syntax::ptr::P; diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 31c0fea5c2d..7ca4251e4c8 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -45,8 +45,8 @@ use super::structurally_resolved_type; use lint; use middle::def_id::DefId; -use middle::ty::{self, Ty, TypeFoldable}; -use middle::ty::cast::{CastKind, CastTy}; +use rustc::ty::{self, Ty, TypeFoldable}; +use rustc::ty::cast::{CastKind, CastTy}; use syntax::codemap::Span; use rustc_front::hir; use syntax::ast; @@ -238,8 +238,8 @@ impl<'tcx> CastCheck<'tcx> { /// can return Ok and create type errors in the fcx rather than returning /// directly. coercion-cast is handled in check instead of here. fn do_check<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result { - use middle::ty::cast::IntTy::*; - use middle::ty::cast::CastTy::*; + use rustc::ty::cast::IntTy::*; + use rustc::ty::cast::CastTy::*; let (t_from, t_cast) = match (CastTy::from_ty(self.expr_ty), CastTy::from_ty(self.cast_ty)) { diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 54b2c8c5923..9333b10d27e 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -13,8 +13,8 @@ use super::{check_fn, Expectation, FnCtxt}; use astconv; -use middle::ty::subst; -use middle::ty::{self, ToPolyTraitRef, Ty}; +use rustc::ty::subst; +use rustc::ty::{self, ToPolyTraitRef, Ty}; use std::cmp; use syntax::abi::Abi; use rustc_front::hir; diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index c62922a33de..dad7d7cd26c 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -62,16 +62,16 @@ use check::{autoderef, FnCtxt, UnresolvedTypeAction}; -use middle::infer::{Coercion, TypeOrigin, TypeTrace}; -use middle::traits::{self, ObligationCause}; -use middle::traits::{predicate_for_trait_def, report_selection_error}; -use middle::ty::adjustment::{AutoAdjustment, AutoDerefRef, AdjustDerefRef}; -use middle::ty::adjustment::{AutoPtr, AutoUnsafe, AdjustReifyFnPointer}; -use middle::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer}; -use middle::ty::{self, LvaluePreference, TypeAndMut, Ty, TyCtxt}; -use middle::ty::fold::TypeFoldable; -use middle::ty::error::TypeError; -use middle::ty::relate::{relate_substs, Relate, RelateResult, TypeRelation}; +use rustc::infer::{Coercion, TypeOrigin, TypeTrace}; +use rustc::traits::{self, ObligationCause}; +use rustc::traits::{predicate_for_trait_def, report_selection_error}; +use rustc::ty::adjustment::{AutoAdjustment, AutoDerefRef, AdjustDerefRef}; +use rustc::ty::adjustment::{AutoPtr, AutoUnsafe, AdjustReifyFnPointer}; +use rustc::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer}; +use rustc::ty::{self, LvaluePreference, TypeAndMut, Ty, TyCtxt}; +use rustc::ty::fold::TypeFoldable; +use rustc::ty::error::TypeError; +use rustc::ty::relate::{relate_substs, Relate, RelateResult, TypeRelation}; use util::common::indent; use std::cell::RefCell; diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index eee3fddcaea..6d429fa7b73 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -9,10 +9,10 @@ // except according to those terms. use middle::free_region::FreeRegionMap; -use middle::infer::{self, TypeOrigin}; -use middle::ty::{self, TyCtxt}; -use middle::traits::{self, ProjectionMode}; -use middle::ty::subst::{self, Subst, Substs, VecPerParamSpace}; +use rustc::infer::{self, TypeOrigin}; +use rustc::ty::{self, TyCtxt}; +use rustc::traits::{self, ProjectionMode}; +use rustc::ty::subst::{self, Subst, Substs, VecPerParamSpace}; use syntax::ast; use syntax::codemap::Span; diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 1f61198bef9..d8bdf6c61aa 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -10,8 +10,8 @@ use check::{coercion, FnCtxt}; -use middle::ty::Ty; -use middle::infer::TypeOrigin; +use rustc::ty::Ty; +use rustc::infer::TypeOrigin; use syntax::codemap::Span; use rustc_front::hir; diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index fd5d06ea9d1..bf2388ab793 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -12,11 +12,11 @@ use check::regionck::{self, Rcx}; use middle::def_id::DefId; use middle::free_region::FreeRegionMap; -use middle::infer; +use rustc::infer; use middle::region; -use middle::ty::subst::{self, Subst}; -use middle::ty::{self, Ty, TyCtxt}; -use middle::traits::{self, ProjectionMode}; +use rustc::ty::subst::{self, Subst}; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::traits::{self, ProjectionMode}; use util::nodemap::FnvHashSet; use syntax::ast; diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 9440be50e21..8720469a724 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -13,10 +13,10 @@ use astconv::AstConv; use intrinsics; -use middle::ty::subst::{self, Substs}; -use middle::ty::FnSig; -use middle::ty::{self, Ty, TyCtxt}; -use middle::ty::fold::TypeFolder; +use rustc::ty::subst::{self, Substs}; +use rustc::ty::FnSig; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::fold::TypeFolder; use {CrateCtxt, require_same_types}; use std::collections::{HashMap}; diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index b8c1d43b7c4..310245f0a0e 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -13,13 +13,13 @@ use super::probe; use check::{self, FnCtxt, callee, demand}; use check::UnresolvedTypeAction; use middle::def_id::DefId; -use middle::ty::subst::{self}; -use middle::traits; -use middle::ty::{self, NoPreference, PreferMutLvalue, Ty, TyCtxt}; -use middle::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr}; -use middle::ty::fold::TypeFoldable; -use middle::infer; -use middle::infer::{InferCtxt, TypeOrigin}; +use rustc::ty::subst::{self}; +use rustc::traits; +use rustc::ty::{self, NoPreference, PreferMutLvalue, Ty, TyCtxt}; +use rustc::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr}; +use rustc::ty::fold::TypeFoldable; +use rustc::infer; +use rustc::infer::{InferCtxt, TypeOrigin}; use syntax::codemap::Span; use rustc_front::hir; diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 6648236f33a..11f7feba86b 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -14,11 +14,11 @@ use astconv::AstConv; use check::FnCtxt; use middle::def::Def; use middle::def_id::DefId; -use middle::ty::subst; -use middle::traits; -use middle::ty::{self, TyCtxt, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable}; -use middle::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr}; -use middle::infer; +use rustc::ty::subst; +use rustc::traits; +use rustc::ty::{self, TyCtxt, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable}; +use rustc::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr}; +use rustc::infer; use syntax::ast; use syntax::codemap::Span; diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 6be822aebca..4b42846297b 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -16,12 +16,12 @@ use super::suggest; use check; use check::{FnCtxt, UnresolvedTypeAction}; use middle::def_id::DefId; -use middle::ty::subst; -use middle::ty::subst::Subst; -use middle::traits; -use middle::ty::{self, NoPreference, Ty, TyCtxt, ToPolyTraitRef, TraitRef, TypeFoldable}; -use middle::infer; -use middle::infer::{InferCtxt, TypeOrigin}; +use rustc::ty::subst; +use rustc::ty::subst::Subst; +use rustc::traits; +use rustc::ty::{self, NoPreference, Ty, TyCtxt, ToPolyTraitRef, TraitRef, TypeFoldable}; +use rustc::infer; +use rustc::infer::{InferCtxt, TypeOrigin}; use syntax::ast; use syntax::codemap::{Span, DUMMY_SP}; use rustc_front::hir; diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index b940c073a7f..aae7912cace 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -16,13 +16,13 @@ use CrateCtxt; use astconv::AstConv; use check::{self, FnCtxt}; use front::map as hir_map; -use middle::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TypeFoldable}; +use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TypeFoldable}; use middle::cstore::{self, CrateStore}; use middle::def::Def; use middle::def_id::DefId; use middle::lang_items::FnOnceTraitLangItem; -use middle::ty::subst::Substs; -use middle::traits::{Obligation, SelectionContext}; +use rustc::ty::subst::Substs; +use rustc::traits::{Obligation, SelectionContext}; use util::nodemap::{FnvHashSet}; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 8d025e16422..c5a0657594e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -88,21 +88,21 @@ use middle::astconv_util::prohibit_type_params; use middle::cstore::LOCAL_CRATE; use middle::def::{self, Def}; use middle::def_id::DefId; -use middle::infer; -use middle::infer::{TypeOrigin, TypeTrace, type_variable}; +use rustc::infer; +use rustc::infer::{TypeOrigin, TypeTrace, type_variable}; use middle::pat_util::{self, pat_id_map}; -use middle::ty::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace}; -use middle::traits::{self, report_fulfillment_errors, ProjectionMode}; -use middle::ty::{GenericPredicates, TypeScheme}; -use middle::ty::{ParamTy, ParameterEnvironment}; -use middle::ty::{LvaluePreference, NoPreference, PreferMutLvalue}; -use middle::ty::{self, ToPolyTraitRef, Ty, TyCtxt}; -use middle::ty::{MethodCall, MethodCallee}; -use middle::ty::adjustment; -use middle::ty::error::TypeError; -use middle::ty::fold::{TypeFolder, TypeFoldable}; -use middle::ty::relate::TypeRelation; -use middle::ty::util::{Representability, IntTypeExt}; +use rustc::ty::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace}; +use rustc::traits::{self, report_fulfillment_errors, ProjectionMode}; +use rustc::ty::{GenericPredicates, TypeScheme}; +use rustc::ty::{ParamTy, ParameterEnvironment}; +use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue}; +use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt}; +use rustc::ty::{MethodCall, MethodCallee}; +use rustc::ty::adjustment; +use rustc::ty::error::TypeError; +use rustc::ty::fold::{TypeFolder, TypeFoldable}; +use rustc::ty::relate::TypeRelation; +use rustc::ty::util::{Representability, IntTypeExt}; use require_c_abi_if_variadic; use rscope::{ElisionFailureInfo, RegionScope}; use session::{Session, CompileResult}; @@ -1769,8 +1769,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Apply "fallbacks" to some types /// ! gets replaced with (), unconstrained ints with i32, and unconstrained floats with f64. fn default_type_parameters(&self) { - use middle::ty::error::UnconstrainedNumeric::Neither; - use middle::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; + use rustc::ty::error::UnconstrainedNumeric::Neither; + use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; for ty in &self.infcx().unsolved_variables() { let resolved = self.infcx().resolve_type_vars_if_possible(ty); if self.infcx().type_var_diverges(resolved) { @@ -1805,8 +1805,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn new_select_all_obligations_and_apply_defaults(&self) { - use middle::ty::error::UnconstrainedNumeric::Neither; - use middle::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; + use rustc::ty::error::UnconstrainedNumeric::Neither; + use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; // For the time being this errs on the side of being memory wasteful but provides better // error reporting. @@ -1978,8 +1978,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { default_map: &FnvHashMap<&Ty<'tcx>, type_variable::Default<'tcx>>, conflict: Ty<'tcx>) -> Option> { - use middle::ty::error::UnconstrainedNumeric::Neither; - use middle::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; + use rustc::ty::error::UnconstrainedNumeric::Neither; + use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; // Ensure that we apply the conflicting default first let mut unbound_tyvars = Vec::with_capacity(unbound_vars.len() + 1); diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index f4841b75d13..281564af615 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -19,7 +19,7 @@ use super::{ FnCtxt, }; use middle::def_id::DefId; -use middle::ty::{Ty, TypeFoldable, PreferMutLvalue}; +use rustc::ty::{Ty, TypeFoldable, PreferMutLvalue}; use syntax::ast; use syntax::parse::token; use rustc_front::hir; @@ -335,7 +335,7 @@ fn lookup_op_method<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, let method_ty = method.ty; // HACK(eddyb) Fully qualified path to work around a resolve bug. - let method_call = ::middle::ty::MethodCall::expr(expr.id); + let method_call = ::rustc::ty::MethodCall::expr(expr.id); fcx.inh.tables.borrow_mut().method_map.insert(method_call, method); // extract return type for method; all late bound regions diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index afbe511dda8..533d24686e7 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -89,13 +89,13 @@ use middle::free_region::FreeRegionMap; use middle::mem_categorization as mc; use middle::mem_categorization::Categorization; use middle::region::{self, CodeExtent}; -use middle::ty::subst::Substs; -use middle::traits; -use middle::ty::{self, Ty, TyCtxt, MethodCall, TypeFoldable}; -use middle::infer::{self, GenericKind, InferCtxt, SubregionOrigin, TypeOrigin, VerifyBound}; +use rustc::ty::subst::Substs; +use rustc::traits; +use rustc::ty::{self, Ty, TyCtxt, MethodCall, TypeFoldable}; +use rustc::infer::{self, GenericKind, InferCtxt, SubregionOrigin, TypeOrigin, VerifyBound}; use middle::pat_util; -use middle::ty::adjustment; -use middle::ty::wf::ImpliedBound; +use rustc::ty::adjustment; +use rustc::ty::wf::ImpliedBound; use std::mem; use syntax::ast; diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 2bb8c874d20..69e49e6a986 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -46,8 +46,8 @@ use check::demand; use middle::expr_use_visitor as euv; use middle::mem_categorization as mc; use middle::mem_categorization::Categorization; -use middle::ty::{self, Ty, TyCtxt}; -use middle::infer::{InferCtxt, UpvarRegion}; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::infer::{InferCtxt, UpvarRegion}; use std::collections::HashSet; use syntax::ast; use syntax::codemap::Span; diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index af33b6b394e..047dfec1796 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -14,10 +14,10 @@ use constrained_type_params::{identify_constrained_type_params, Parameter}; use CrateCtxt; use middle::def_id::DefId; use middle::region::{CodeExtent}; -use middle::ty::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace}; -use middle::traits; -use middle::ty::{self, Ty, TyCtxt}; -use middle::ty::fold::{TypeFolder}; +use rustc::ty::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace}; +use rustc::traits; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::fold::{TypeFolder}; use std::cell::RefCell; use std::collections::HashSet; diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 20c86f9a17c..7ede85454e9 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -17,10 +17,10 @@ use astconv::AstConv; use check::FnCtxt; use middle::def_id::DefId; use middle::pat_util; -use middle::ty::{self, Ty, TyCtxt, MethodCall, MethodCallee}; -use middle::ty::adjustment; -use middle::ty::fold::{TypeFolder,TypeFoldable}; -use middle::infer; +use rustc::ty::{self, Ty, TyCtxt, MethodCall, MethodCallee}; +use rustc::ty::adjustment; +use rustc::ty::fold::{TypeFolder,TypeFoldable}; +use rustc::infer; use write_substs_to_tcx; use write_ty_to_tcx; diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index af497509105..c3b46ef83ac 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -17,21 +17,21 @@ use middle::def_id::DefId; use middle::lang_items::UnsizeTraitLangItem; -use middle::ty::subst::{self, Subst}; -use middle::ty::{self, TyCtxt, TypeFoldable}; -use middle::traits::{self, ProjectionMode}; -use middle::ty::{ImplOrTraitItemId, ConstTraitItemId}; -use middle::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment}; -use middle::ty::{Ty, TyBool, TyChar, TyEnum, TyError}; -use middle::ty::{TyParam, TyRawPtr}; -use middle::ty::{TyRef, TyStruct, TyTrait, TyTuple}; -use middle::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt}; -use middle::ty::{TyUint, TyClosure, TyBox, TyFnDef, TyFnPtr}; -use middle::ty::TyProjection; -use middle::ty::util::CopyImplementationError; +use rustc::ty::subst::{self, Subst}; +use rustc::ty::{self, TyCtxt, TypeFoldable}; +use rustc::traits::{self, ProjectionMode}; +use rustc::ty::{ImplOrTraitItemId, ConstTraitItemId}; +use rustc::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment}; +use rustc::ty::{Ty, TyBool, TyChar, TyEnum, TyError}; +use rustc::ty::{TyParam, TyRawPtr}; +use rustc::ty::{TyRef, TyStruct, TyTrait, TyTuple}; +use rustc::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt}; +use rustc::ty::{TyUint, TyClosure, TyBox, TyFnDef, TyFnPtr}; +use rustc::ty::TyProjection; +use rustc::ty::util::CopyImplementationError; use middle::free_region::FreeRegionMap; use CrateCtxt; -use middle::infer::{self, InferCtxt, TypeOrigin, new_infer_ctxt}; +use rustc::infer::{self, InferCtxt, TypeOrigin, new_infer_ctxt}; use std::cell::RefCell; use std::rc::Rc; use syntax::ast; diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 56e6d039903..eba3e56c722 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -13,8 +13,8 @@ use middle::cstore::LOCAL_CRATE; use middle::def_id::DefId; -use middle::traits; -use middle::ty::{self, TyCtxt}; +use rustc::traits; +use rustc::ty::{self, TyCtxt}; use syntax::ast; use syntax::codemap::Span; use rustc::dep_graph::DepNode; diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index 78ae8fa65f8..d7d4560a4ea 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -14,9 +14,9 @@ use middle::cstore::CrateStore; use middle::def_id::DefId; -use middle::traits::{self, ProjectionMode}; -use middle::infer; -use middle::ty::{self, TyCtxt}; +use rustc::traits::{self, ProjectionMode}; +use rustc::infer; +use rustc::ty::{self, TyCtxt}; use syntax::ast; use rustc::dep_graph::DepNode; use rustc_front::hir; diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs index fbb1653b06a..6d77200daa3 100644 --- a/src/librustc_typeck/coherence/unsafety.rs +++ b/src/librustc_typeck/coherence/unsafety.rs @@ -11,7 +11,7 @@ //! Unsafety checker: every impl either implements a trait defined in this //! crate or pertains to a type defined in this crate. -use middle::ty::TyCtxt; +use rustc::ty::TyCtxt; use rustc_front::intravisit; use rustc_front::hir; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index a282165d1a0..0b447b2009b 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -68,12 +68,12 @@ use middle::lang_items::SizedTraitLangItem; use middle::resolve_lifetime; use middle::const_eval::{self, ConstVal}; use middle::const_eval::EvalHint::UncheckedExprHint; -use middle::ty::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace}; -use middle::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; -use middle::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeScheme}; -use middle::ty::{VariantKind}; -use middle::ty::fold::{TypeFolder}; -use middle::ty::util::IntTypeExt; +use rustc::ty::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace}; +use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; +use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeScheme}; +use rustc::ty::{VariantKind}; +use rustc::ty::fold::{TypeFolder}; +use rustc::ty::util::IntTypeExt; use rscope::*; use rustc::dep_graph::DepNode; use rustc::front::map as hir_map; diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs index 016ff3b5a06..7e8b08c5853 100644 --- a/src/librustc_typeck/constrained_type_params.rs +++ b/src/librustc_typeck/constrained_type_params.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::ty::subst; -use middle::ty::{self, Ty, TyCtxt}; +use rustc::ty::subst; +use rustc::ty::{self, Ty, TyCtxt}; use std::collections::HashSet; diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index ccc79b0748c..9b0fdd8a2e3 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -104,10 +104,10 @@ pub use rustc::util; use dep_graph::DepNode; use front::map as hir_map; use middle::def::Def; -use middle::infer::{self, TypeOrigin}; -use middle::ty::subst::Substs; -use middle::ty::{self, Ty, TyCtxt, TypeFoldable}; -use middle::traits::ProjectionMode; +use rustc::infer::{self, TypeOrigin}; +use rustc::ty::subst::Substs; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc::traits::ProjectionMode; use session::{config, CompileResult}; use util::common::time; use rustc_front::hir; diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index 1b02c736dce..793dba1e3f5 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -9,7 +9,7 @@ // except according to those terms. -use middle::ty; +use rustc::ty; use std::cell::Cell; use syntax::codemap::Span; diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index f46edb03b95..1ed355c90a5 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -16,10 +16,10 @@ use dep_graph::DepTrackingMapConfig; use middle::def_id::DefId; use middle::resolve_lifetime as rl; -use middle::ty::subst; -use middle::ty::subst::ParamSpace; -use middle::ty::{self, Ty, TyCtxt}; -use middle::ty::maps::ItemVariances; +use rustc::ty::subst; +use rustc::ty::subst::ParamSpace; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::maps::ItemVariances; use rustc::front::map as hir_map; use syntax::ast; use rustc_front::hir; diff --git a/src/librustc_typeck/variance/mod.rs b/src/librustc_typeck/variance/mod.rs index ab37ef952c9..ee9f317f20f 100644 --- a/src/librustc_typeck/variance/mod.rs +++ b/src/librustc_typeck/variance/mod.rs @@ -12,7 +12,7 @@ //! parameters. See README.md for details. use arena; -use middle::ty::TyCtxt; +use rustc::ty::TyCtxt; /// Defines the `TermsContext` basically houses an arena where we can /// allocate terms. diff --git a/src/librustc_typeck/variance/solve.rs b/src/librustc_typeck/variance/solve.rs index c5e925226d0..0763cfd7e2e 100644 --- a/src/librustc_typeck/variance/solve.rs +++ b/src/librustc_typeck/variance/solve.rs @@ -15,8 +15,8 @@ //! optimal solution to the constraints. The final variance for each //! inferred is then written into the `variance_map` in the tcx. -use middle::ty::subst::VecPerParamSpace; -use middle::ty; +use rustc::ty::subst::VecPerParamSpace; +use rustc::ty; use std::rc::Rc; use super::constraints::*; diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index 7148afb5e85..c6f82ba42e6 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -21,9 +21,9 @@ use arena::TypedArena; use dep_graph::DepTrackingMapConfig; -use middle::ty::subst::{ParamSpace, FnSpace, TypeSpace, SelfSpace, VecPerParamSpace}; -use middle::ty::{self, TyCtxt}; -use middle::ty::maps::ItemVariances; +use rustc::ty::subst::{ParamSpace, FnSpace, TypeSpace, SelfSpace, VecPerParamSpace}; +use rustc::ty::{self, TyCtxt}; +use rustc::ty::maps::ItemVariances; use std::fmt; use std::rc::Rc; use syntax::ast; diff --git a/src/librustc_typeck/variance/xform.rs b/src/librustc_typeck/variance/xform.rs index 2749dce5c73..02a2ceb360d 100644 --- a/src/librustc_typeck/variance/xform.rs +++ b/src/librustc_typeck/variance/xform.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::ty; +use rustc::ty; pub trait Xform { fn xform(self, v: Self) -> Self; diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 75bf1036fa2..94dead3c005 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -19,8 +19,8 @@ use rustc_front::hir; use rustc::middle::cstore::{self, CrateStore}; use rustc::middle::def::Def; use rustc::middle::def_id::DefId; -use rustc::middle::ty::{self, TyCtxt}; -use rustc::middle::ty::subst; +use rustc::ty::{self, TyCtxt}; +use rustc::ty::subst; use rustc::middle::stability; use rustc::middle::const_eval; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 17fde1c7b33..e56286c8bed 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -38,8 +38,8 @@ use rustc_trans::back::link; use rustc::middle::cstore::{self, CrateStore}; use rustc::middle::def::Def; use rustc::middle::def_id::{DefId, DefIndex}; -use rustc::middle::ty::subst::{self, ParamSpace, VecPerParamSpace}; -use rustc::middle::ty; +use rustc::ty::subst::{self, ParamSpace, VecPerParamSpace}; +use rustc::ty; use rustc::middle::stability; use rustc_front::hir; @@ -831,7 +831,7 @@ impl Clean for hir::WherePredicate { impl<'a> Clean for ty::Predicate<'a> { fn clean(&self, cx: &DocContext) -> WherePredicate { - use rustc::middle::ty::Predicate; + use rustc::ty::Predicate; match *self { Predicate::Trait(ref pred) => pred.clean(cx), diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 4cce8358992..e6a4d882c04 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -11,7 +11,7 @@ //! Simplification of where clauses and parameter bounds into a prettier and //! more canonical form. //! -//! Currently all cross-crate-inlined function use `middle::ty` to reconstruct +//! Currently all cross-crate-inlined function use `rustc::ty` to reconstruct //! the AST (e.g. see all of `clean::inline`), but this is not always a //! non-lossy transformation. The current format of storage for where clauses //! for functions and such is simply a list of predicates. One example of this @@ -30,7 +30,7 @@ use std::mem; use std::collections::HashMap; use rustc::middle::def_id::DefId; -use rustc::middle::ty::subst; +use rustc::ty::subst; use clean::PathParameters as PP; use clean::WherePredicate as WP; diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index c30fd39616c..15a10a84e43 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -15,7 +15,7 @@ use rustc::dep_graph::DepGraph; use rustc::session::{self, config}; use rustc::middle::def_id::DefId; use rustc::middle::privacy::AccessLevels; -use rustc::middle::ty::{self, TyCtxt}; +use rustc::ty::{self, TyCtxt}; use rustc::front::map as hir_map; use rustc::lint; use rustc_trans::back::link; diff --git a/src/test/auxiliary/dummy_mir_pass.rs b/src/test/auxiliary/dummy_mir_pass.rs index fdfbc98b007..3e1b46522a9 100644 --- a/src/test/auxiliary/dummy_mir_pass.rs +++ b/src/test/auxiliary/dummy_mir_pass.rs @@ -22,7 +22,7 @@ extern crate syntax; use rustc::mir::transform::{self, MirPass}; use rustc::mir::repr::{Mir, Literal}; use rustc::mir::visit::MutVisitor; -use rustc::middle::ty; +use rustc::ty; use rustc::middle::const_eval::ConstVal; use rustc_const_eval::ConstInt; use rustc_plugin::Registry; diff --git a/src/test/compile-fail/moves-based-on-type-cyclic-types-issue-4821.rs b/src/test/compile-fail/moves-based-on-type-cyclic-types-issue-4821.rs index 865784c2f1e..0c4aae8cfad 100644 --- a/src/test/compile-fail/moves-based-on-type-cyclic-types-issue-4821.rs +++ b/src/test/compile-fail/moves-based-on-type-cyclic-types-issue-4821.rs @@ -10,7 +10,7 @@ // Test for a subtle failure computing kinds of cyclic types, in which // temporary kinds wound up being stored in a cache and used later. -// See middle::ty::type_contents() for more information. +// See rustc::ty::type_contents() for more information. struct List { key: isize, next: Option> } diff --git a/src/test/run-make/execution-engine/test.rs b/src/test/run-make/execution-engine/test.rs index 4ff531d4755..7454bbfb531 100644 --- a/src/test/run-make/execution-engine/test.rs +++ b/src/test/run-make/execution-engine/test.rs @@ -30,7 +30,7 @@ use rustc::dep_graph::DepGraph; use rustc::front::map as ast_map; use rustc::llvm; use rustc::middle::cstore::{CrateStore, LinkagePreference}; -use rustc::middle::ty; +use rustc::ty; use rustc::session::config::{self, basic_options, build_configuration, Input, Options}; use rustc::session::build_session; use rustc_driver::{driver, abort_on_err}; -- cgit 1.4.1-3-g733a5

(&self, value: P) -> Obligation<'tcx,P> { - Obligation { cause: self.cause.clone(), - recursion_depth: self.recursion_depth, - predicate: value } - } -} - -impl<'tcx> ObligationCause<'tcx> { - pub fn new(span: Span, - body_id: ast::NodeId, - code: ObligationCauseCode<'tcx>) - -> ObligationCause<'tcx> { - ObligationCause { span: span, body_id: body_id, code: code } - } - - pub fn misc(span: Span, body_id: ast::NodeId) -> ObligationCause<'tcx> { - ObligationCause { span: span, body_id: body_id, code: MiscObligation } - } - - pub fn dummy() -> ObligationCause<'tcx> { - ObligationCause { span: DUMMY_SP, body_id: 0, code: MiscObligation } - } -} - -impl<'tcx, N> Vtable<'tcx, N> { - pub fn nested_obligations(self) -> Vec { - match self { - VtableImpl(i) => i.nested, - VtableParam(n) => n, - VtableBuiltin(i) => i.nested, - VtableDefaultImpl(d) => d.nested, - VtableClosure(c) => c.nested, - VtableObject(_) | VtableFnPointer(..) => vec![] - } - } - - pub fn map(self, f: F) -> Vtable<'tcx, M> where F: FnMut(N) -> M { - match self { - VtableImpl(i) => VtableImpl(VtableImplData { - impl_def_id: i.impl_def_id, - substs: i.substs, - nested: i.nested.into_iter().map(f).collect() - }), - VtableParam(n) => VtableParam(n.into_iter().map(f).collect()), - VtableBuiltin(i) => VtableBuiltin(VtableBuiltinData { - nested: i.nested.into_iter().map(f).collect() - }), - VtableObject(o) => VtableObject(o), - VtableDefaultImpl(d) => VtableDefaultImpl(VtableDefaultImplData { - trait_def_id: d.trait_def_id, - nested: d.nested.into_iter().map(f).collect() - }), - VtableFnPointer(f) => VtableFnPointer(f), - VtableClosure(c) => VtableClosure(VtableClosureData { - closure_def_id: c.closure_def_id, - substs: c.substs, - nested: c.nested.into_iter().map(f).collect(), - }) - } - } -} - -impl<'tcx> FulfillmentError<'tcx> { - fn new(obligation: PredicateObligation<'tcx>, - code: FulfillmentErrorCode<'tcx>) - -> FulfillmentError<'tcx> - { - FulfillmentError { obligation: obligation, code: code } - } -} - -impl<'tcx> TraitObligation<'tcx> { - fn self_ty(&self) -> ty::Binder> { - ty::Binder(self.predicate.skip_binder().self_ty()) - } -} diff --git a/src/librustc/middle/traits/object_safety.rs b/src/librustc/middle/traits/object_safety.rs deleted file mode 100644 index 8777b9eb00c..00000000000 --- a/src/librustc/middle/traits/object_safety.rs +++ /dev/null @@ -1,379 +0,0 @@ -// Copyright 2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! "Object safety" refers to the ability for a trait to be converted -//! to an object. In general, traits may only be converted to an -//! object if all of their methods meet certain criteria. In particular, -//! they must: -//! -//! - have a suitable receiver from which we can extract a vtable; -//! - not reference the erased type `Self` except for in this receiver; -//! - not have generic type parameters - -use super::supertraits; -use super::elaborate_predicates; - -use middle::def_id::DefId; -use middle::ty::subst::{self, SelfSpace, TypeSpace}; -use middle::traits; -use middle::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; -use std::rc::Rc; -use syntax::ast; - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub enum ObjectSafetyViolation<'tcx> { - /// Self : Sized declared on the trait - SizedSelf, - - /// Supertrait reference references `Self` an in illegal location - /// (e.g. `trait Foo : Bar`) - SupertraitSelf, - - /// Method has something illegal - Method(Rc>, MethodViolationCode), -} - -/// Reasons a method might not be object-safe. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum MethodViolationCode { - /// e.g., `fn foo()` - StaticMethod, - - /// e.g., `fn foo(&self, x: Self)` or `fn foo(&self) -> Self` - ReferencesSelf, - - /// e.g., `fn foo()` - Generic, -} - -pub fn is_object_safe<'tcx>(tcx: &TyCtxt<'tcx>, - trait_def_id: DefId) - -> bool -{ - // Because we query yes/no results frequently, we keep a cache: - let def = tcx.lookup_trait_def(trait_def_id); - - let result = def.object_safety().unwrap_or_else(|| { - let result = object_safety_violations(tcx, trait_def_id).is_empty(); - - // Record just a yes/no result in the cache; this is what is - // queried most frequently. Note that this may overwrite a - // previous result, but always with the same thing. - def.set_object_safety(result); - - result - }); - - debug!("is_object_safe({:?}) = {}", trait_def_id, result); - - result -} - -/// Returns the object safety violations that affect -/// astconv - currently, Self in supertraits. This is needed -/// because `object_safety_violations` can't be used during -/// type collection. -pub fn astconv_object_safety_violations<'tcx>(tcx: &TyCtxt<'tcx>, - trait_def_id: DefId) - -> Vec> -{ - let mut violations = vec![]; - - if supertraits_reference_self(tcx, trait_def_id) { - violations.push(ObjectSafetyViolation::SupertraitSelf); - } - - debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}", - trait_def_id, - violations); - - violations -} - -pub fn object_safety_violations<'tcx>(tcx: &TyCtxt<'tcx>, - trait_def_id: DefId) - -> Vec> -{ - traits::supertrait_def_ids(tcx, trait_def_id) - .flat_map(|def_id| object_safety_violations_for_trait(tcx, def_id)) - .collect() -} - -fn object_safety_violations_for_trait<'tcx>(tcx: &TyCtxt<'tcx>, - trait_def_id: DefId) - -> Vec> -{ - // Check methods for violations. - let mut violations: Vec<_> = - tcx.trait_items(trait_def_id).iter() - .filter_map(|item| { - match *item { - ty::MethodTraitItem(ref m) => { - object_safety_violation_for_method(tcx, trait_def_id, &m) - .map(|code| ObjectSafetyViolation::Method(m.clone(), code)) - } - _ => None, - } - }) - .collect(); - - // Check the trait itself. - if trait_has_sized_self(tcx, trait_def_id) { - violations.push(ObjectSafetyViolation::SizedSelf); - } - if supertraits_reference_self(tcx, trait_def_id) { - violations.push(ObjectSafetyViolation::SupertraitSelf); - } - - debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}", - trait_def_id, - violations); - - violations -} - -pub fn supertraits_reference_self<'tcx>(tcx: &TyCtxt<'tcx>, - trait_def_id: DefId) - -> bool -{ - let trait_def = tcx.lookup_trait_def(trait_def_id); - let trait_ref = trait_def.trait_ref.clone(); - let trait_ref = trait_ref.to_poly_trait_ref(); - let predicates = tcx.lookup_super_predicates(trait_def_id); - predicates - .predicates - .into_iter() - .map(|predicate| predicate.subst_supertrait(tcx, &trait_ref)) - .any(|predicate| { - match predicate { - ty::Predicate::Trait(ref data) => { - // In the case of a trait predicate, we can skip the "self" type. - data.0.trait_ref.substs.types.get_slice(TypeSpace) - .iter() - .cloned() - .any(|t| t.has_self_ty()) - } - ty::Predicate::Projection(..) | - ty::Predicate::WellFormed(..) | - ty::Predicate::ObjectSafe(..) | - ty::Predicate::TypeOutlives(..) | - ty::Predicate::RegionOutlives(..) | - ty::Predicate::Equate(..) => { - false - } - } - }) -} - -fn trait_has_sized_self<'tcx>(tcx: &TyCtxt<'tcx>, - trait_def_id: DefId) - -> bool -{ - let trait_def = tcx.lookup_trait_def(trait_def_id); - let trait_predicates = tcx.lookup_predicates(trait_def_id); - generics_require_sized_self(tcx, &trait_def.generics, &trait_predicates) -} - -fn generics_require_sized_self<'tcx>(tcx: &TyCtxt<'tcx>, - generics: &ty::Generics<'tcx>, - predicates: &ty::GenericPredicates<'tcx>) - -> bool -{ - let sized_def_id = match tcx.lang_items.sized_trait() { - Some(def_id) => def_id, - None => { return false; /* No Sized trait, can't require it! */ } - }; - - // Search for a predicate like `Self : Sized` amongst the trait bounds. - let free_substs = tcx.construct_free_substs(generics, - tcx.region_maps.node_extent(ast::DUMMY_NODE_ID)); - let predicates = predicates.instantiate(tcx, &free_substs).predicates.into_vec(); - elaborate_predicates(tcx, predicates) - .any(|predicate| { - match predicate { - ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => { - trait_pred.0.self_ty().is_self() - } - ty::Predicate::Projection(..) | - ty::Predicate::Trait(..) | - ty::Predicate::Equate(..) | - ty::Predicate::RegionOutlives(..) | - ty::Predicate::WellFormed(..) | - ty::Predicate::ObjectSafe(..) | - ty::Predicate::TypeOutlives(..) => { - false - } - } - }) -} - -/// Returns `Some(_)` if this method makes the containing trait not object safe. -fn object_safety_violation_for_method<'tcx>(tcx: &TyCtxt<'tcx>, - trait_def_id: DefId, - method: &ty::Method<'tcx>) - -> Option -{ - // Any method that has a `Self : Sized` requisite is otherwise - // exempt from the regulations. - if generics_require_sized_self(tcx, &method.generics, &method.predicates) { - return None; - } - - virtual_call_violation_for_method(tcx, trait_def_id, method) -} - -/// We say a method is *vtable safe* if it can be invoked on a trait -/// object. Note that object-safe traits can have some -/// non-vtable-safe methods, so long as they require `Self:Sized` or -/// otherwise ensure that they cannot be used when `Self=Trait`. -pub fn is_vtable_safe_method<'tcx>(tcx: &TyCtxt<'tcx>, - trait_def_id: DefId, - method: &ty::Method<'tcx>) - -> bool -{ - virtual_call_violation_for_method(tcx, trait_def_id, method).is_none() -} - -/// Returns `Some(_)` if this method cannot be called on a trait -/// object; this does not necessarily imply that the enclosing trait -/// is not object safe, because the method might have a where clause -/// `Self:Sized`. -fn virtual_call_violation_for_method<'tcx>(tcx: &TyCtxt<'tcx>, - trait_def_id: DefId, - method: &ty::Method<'tcx>) - -> Option -{ - // The method's first parameter must be something that derefs (or - // autorefs) to `&self`. For now, we only accept `self`, `&self` - // and `Box`. - match method.explicit_self { - ty::ExplicitSelfCategory::Static => { - return Some(MethodViolationCode::StaticMethod); - } - - ty::ExplicitSelfCategory::ByValue | - ty::ExplicitSelfCategory::ByReference(..) | - ty::ExplicitSelfCategory::ByBox => { - } - } - - // The `Self` type is erased, so it should not appear in list of - // arguments or return type apart from the receiver. - let ref sig = method.fty.sig; - for &input_ty in &sig.0.inputs[1..] { - if contains_illegal_self_type_reference(tcx, trait_def_id, input_ty) { - return Some(MethodViolationCode::ReferencesSelf); - } - } - if let ty::FnConverging(result_type) = sig.0.output { - if contains_illegal_self_type_reference(tcx, trait_def_id, result_type) { - return Some(MethodViolationCode::ReferencesSelf); - } - } - - // We can't monomorphize things like `fn foo(...)`. - if !method.generics.types.is_empty_in(subst::FnSpace) { - return Some(MethodViolationCode::Generic); - } - - None -} - -fn contains_illegal_self_type_reference<'tcx>(tcx: &TyCtxt<'tcx>, - trait_def_id: DefId, - ty: Ty<'tcx>) - -> bool -{ - // This is somewhat subtle. In general, we want to forbid - // references to `Self` in the argument and return types, - // since the value of `Self` is erased. However, there is one - // exception: it is ok to reference `Self` in order to access - // an associated type of the current trait, since we retain - // the value of those associated types in the object type - // itself. - // - // ```rust - // trait SuperTrait { - // type X; - // } - // - // trait Trait : SuperTrait { - // type Y; - // fn foo(&self, x: Self) // bad - // fn foo(&self) -> Self // bad - // fn foo(&self) -> Option // bad - // fn foo(&self) -> Self::Y // OK, desugars to next example - // fn foo(&self) -> ::Y // OK - // fn foo(&self) -> Self::X // OK, desugars to next example - // fn foo(&self) -> ::X // OK - // } - // ``` - // - // However, it is not as simple as allowing `Self` in a projected - // type, because there are illegal ways to use `Self` as well: - // - // ```rust - // trait Trait : SuperTrait { - // ... - // fn foo(&self) -> ::X; - // } - // ``` - // - // Here we will not have the type of `X` recorded in the - // object type, and we cannot resolve `Self as SomeOtherTrait` - // without knowing what `Self` is. - - let mut supertraits: Option>> = None; - let mut error = false; - ty.maybe_walk(|ty| { - match ty.sty { - ty::TyParam(ref param_ty) => { - if param_ty.space == SelfSpace { - error = true; - } - - false // no contained types to walk - } - - ty::TyProjection(ref data) => { - // This is a projected type `::X`. - - // Compute supertraits of current trait lazily. - if supertraits.is_none() { - let trait_def = tcx.lookup_trait_def(trait_def_id); - let trait_ref = ty::Binder(trait_def.trait_ref.clone()); - supertraits = Some(traits::supertraits(tcx, trait_ref).collect()); - } - - // Determine whether the trait reference `Foo as - // SomeTrait` is in fact a supertrait of the - // current trait. In that case, this type is - // legal, because the type `X` will be specified - // in the object type. Note that we can just use - // direct equality here because all of these types - // are part of the formal parameter listing, and - // hence there should be no inference variables. - let projection_trait_ref = ty::Binder(data.trait_ref.clone()); - let is_supertrait_of_current_trait = - supertraits.as_ref().unwrap().contains(&projection_trait_ref); - - if is_supertrait_of_current_trait { - false // do not walk contained types, do not report error, do collect $200 - } else { - true // DO walk contained types, POSSIBLY reporting an error - } - } - - _ => true, // walk contained types, if any - } - }); - - error -} diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs deleted file mode 100644 index bd075a5dc88..00000000000 --- a/src/librustc/middle/traits/project.rs +++ /dev/null @@ -1,1164 +0,0 @@ -// Copyright 2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Code for projecting associated types out of trait references. - -use super::elaborate_predicates; -use super::report_overflow_error; -use super::specialization_graph; -use super::translate_substs; -use super::Obligation; -use super::ObligationCause; -use super::PredicateObligation; -use super::SelectionContext; -use super::SelectionError; -use super::VtableClosureData; -use super::VtableImplData; -use super::util; - -use middle::def_id::DefId; -use middle::infer::{self, TypeOrigin}; -use middle::ty::subst::Subst; -use middle::ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt}; -use middle::ty::fold::{TypeFoldable, TypeFolder}; -use syntax::parse::token; -use syntax::ast; -use util::common::FN_OUTPUT_NAME; - -use std::rc::Rc; - -/// Depending on the stage of compilation, we want projection to be -/// more or less conservative. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum ProjectionMode { - /// FIXME (#32205) - /// At coherence-checking time, we're still constructing the - /// specialization graph, and thus we only project project - /// non-`default` associated types that are defined directly in - /// the applicable impl. (This behavior should be improved over - /// time, to allow for successful projections modulo cycles - /// between different impls). - /// - /// Here's an example that will fail due to the restriction: - /// - /// ``` - /// trait Assoc { - /// type Output; - /// } - /// - /// impl Assoc for T { - /// type Output = bool; - /// } - /// - /// impl Assoc for u8 {} // <- inherits the non-default type from above - /// - /// trait Foo {} - /// impl Foo for u32 {} - /// impl Foo for ::Output {} // <- this projection will fail - /// ``` - /// - /// The projection would succeed if `Output` had been defined - /// directly in the impl for `u8`. - Topmost, - - /// At type-checking time, we refuse to project any associated - /// type that is marked `default`. Non-`default` ("final") types - /// are always projected. This is necessary in general for - /// soundness of specialization. However, we *could* allow - /// projections in fully-monomorphic cases. We choose not to, - /// because we prefer for `default type` to force the type - /// definition to be treated abstractly by any consumers of the - /// impl. Concretely, that means that the following example will - /// fail to compile: - /// - /// ``` - /// trait Assoc { - /// type Output; - /// } - /// - /// impl Assoc for T { - /// default type Output = bool; - /// } - /// - /// fn main() { - /// let <() as Assoc>::Output = true; - /// } - AnyFinal, - - /// At trans time, all projections will succeed. - Any, -} - -impl ProjectionMode { - pub fn is_topmost(&self) -> bool { - match *self { - ProjectionMode::Topmost => true, - _ => false, - } - } - - pub fn is_any_final(&self) -> bool { - match *self { - ProjectionMode::AnyFinal => true, - _ => false, - } - } - - pub fn is_any(&self) -> bool { - match *self { - ProjectionMode::Any => true, - _ => false, - } - } -} - - -pub type PolyProjectionObligation<'tcx> = - Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>; - -pub type ProjectionObligation<'tcx> = - Obligation<'tcx, ty::ProjectionPredicate<'tcx>>; - -pub type ProjectionTyObligation<'tcx> = - Obligation<'tcx, ty::ProjectionTy<'tcx>>; - -/// When attempting to resolve `::Name` ... -#[derive(Debug)] -pub enum ProjectionTyError<'tcx> { - /// ...we found multiple sources of information and couldn't resolve the ambiguity. - TooManyCandidates, - - /// ...an error occurred matching `T : TraitRef` - TraitSelectionError(SelectionError<'tcx>), -} - -#[derive(Clone)] -pub struct MismatchedProjectionTypes<'tcx> { - pub err: ty::error::TypeError<'tcx> -} - -#[derive(PartialEq, Eq, Debug)] -enum ProjectionTyCandidate<'tcx> { - // from a where-clause in the env or object type - ParamEnv(ty::PolyProjectionPredicate<'tcx>), - - // from the definition of `Trait` when you have something like <::B as Trait2>::C - TraitDef(ty::PolyProjectionPredicate<'tcx>), - - // defined in an impl - Impl(VtableImplData<'tcx, PredicateObligation<'tcx>>), - - // closure return type - Closure(VtableClosureData<'tcx, PredicateObligation<'tcx>>), - - // fn pointer return type - FnPointer(Ty<'tcx>), -} - -struct ProjectionTyCandidateSet<'tcx> { - vec: Vec>, - ambiguous: bool -} - -/// Evaluates constraints of the form: -/// -/// for<...> ::U == V -/// -/// If successful, this may result in additional obligations. -pub fn poly_project_and_unify_type<'cx,'tcx>( - selcx: &mut SelectionContext<'cx,'tcx>, - obligation: &PolyProjectionObligation<'tcx>) - -> Result>>, MismatchedProjectionTypes<'tcx>> -{ - debug!("poly_project_and_unify_type(obligation={:?})", - obligation); - - let infcx = selcx.infcx(); - infcx.commit_if_ok(|snapshot| { - let (skol_predicate, skol_map) = - infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot); - - let skol_obligation = obligation.with(skol_predicate); - match project_and_unify_type(selcx, &skol_obligation) { - Ok(result) => { - match infcx.leak_check(&skol_map, snapshot) { - Ok(()) => Ok(infcx.plug_leaks(skol_map, snapshot, &result)), - Err(e) => Err(MismatchedProjectionTypes { err: e }), - } - } - Err(e) => { - Err(e) - } - } - }) -} - -/// Evaluates constraints of the form: -/// -/// ::U == V -/// -/// If successful, this may result in additional obligations. -fn project_and_unify_type<'cx,'tcx>( - selcx: &mut SelectionContext<'cx,'tcx>, - obligation: &ProjectionObligation<'tcx>) - -> Result>>, MismatchedProjectionTypes<'tcx>> -{ - debug!("project_and_unify_type(obligation={:?})", - obligation); - - let Normalized { value: normalized_ty, obligations } = - match opt_normalize_projection_type(selcx, - obligation.predicate.projection_ty.clone(), - obligation.cause.clone(), - obligation.recursion_depth) { - Some(n) => n, - None => { - consider_unification_despite_ambiguity(selcx, obligation); - return Ok(None); - } - }; - - debug!("project_and_unify_type: normalized_ty={:?} obligations={:?}", - normalized_ty, - obligations); - - let infcx = selcx.infcx(); - let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); - match infer::mk_eqty(infcx, true, origin, normalized_ty, obligation.predicate.ty) { - Ok(()) => Ok(Some(obligations)), - Err(err) => Err(MismatchedProjectionTypes { err: err }), - } -} - -fn consider_unification_despite_ambiguity<'cx,'tcx>(selcx: &mut SelectionContext<'cx,'tcx>, - obligation: &ProjectionObligation<'tcx>) { - debug!("consider_unification_despite_ambiguity(obligation={:?})", - obligation); - - let def_id = obligation.predicate.projection_ty.trait_ref.def_id; - match selcx.tcx().lang_items.fn_trait_kind(def_id) { - Some(_) => { } - None => { return; } - } - - let infcx = selcx.infcx(); - let self_ty = obligation.predicate.projection_ty.trait_ref.self_ty(); - let self_ty = infcx.shallow_resolve(self_ty); - debug!("consider_unification_despite_ambiguity: self_ty.sty={:?}", - self_ty.sty); - match self_ty.sty { - ty::TyClosure(closure_def_id, ref substs) => { - let closure_typer = selcx.closure_typer(); - let closure_type = closure_typer.closure_type(closure_def_id, substs); - let ty::Binder((_, ret_type)) = - util::closure_trait_ref_and_return_type(infcx.tcx, - def_id, - self_ty, - &closure_type.sig, - util::TupleArgumentsFlag::No); - // We don't have to normalize the return type here - this is only - // reached for TyClosure: Fn inputs where the closure kind is - // still unknown, which should only occur in typeck where the - // closure type is already normalized. - let (ret_type, _) = - infcx.replace_late_bound_regions_with_fresh_var( - obligation.cause.span, - infer::AssocTypeProjection(obligation.predicate.projection_ty.item_name), - &ty::Binder(ret_type)); - - debug!("consider_unification_despite_ambiguity: ret_type={:?}", - ret_type); - let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); - let obligation_ty = obligation.predicate.ty; - match infer::mk_eqty(infcx, true, origin, obligation_ty, ret_type) { - Ok(()) => { } - Err(_) => { /* ignore errors */ } - } - } - _ => { } - } -} - -/// Normalizes any associated type projections in `value`, replacing -/// them with a fully resolved type where possible. The return value -/// combines the normalized result and any additional obligations that -/// were incurred as result. -pub fn normalize<'a,'b,'tcx,T>(selcx: &'a mut SelectionContext<'b,'tcx>, - cause: ObligationCause<'tcx>, - value: &T) - -> Normalized<'tcx, T> - where T : TypeFoldable<'tcx> -{ - normalize_with_depth(selcx, cause, 0, value) -} - -/// As `normalize`, but with a custom depth. -pub fn normalize_with_depth<'a,'b,'tcx,T>(selcx: &'a mut SelectionContext<'b,'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, - value: &T) - -> Normalized<'tcx, T> - where T : TypeFoldable<'tcx> -{ - let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, depth); - let result = normalizer.fold(value); - - Normalized { - value: result, - obligations: normalizer.obligations, - } -} - -struct AssociatedTypeNormalizer<'a,'b:'a,'tcx:'b> { - selcx: &'a mut SelectionContext<'b,'tcx>, - cause: ObligationCause<'tcx>, - obligations: Vec>, - depth: usize, -} - -impl<'a,'b,'tcx> AssociatedTypeNormalizer<'a,'b,'tcx> { - fn new(selcx: &'a mut SelectionContext<'b,'tcx>, - cause: ObligationCause<'tcx>, - depth: usize) - -> AssociatedTypeNormalizer<'a,'b,'tcx> - { - AssociatedTypeNormalizer { - selcx: selcx, - cause: cause, - obligations: vec!(), - depth: depth, - } - } - - fn fold>(&mut self, value: &T) -> T { - let value = self.selcx.infcx().resolve_type_vars_if_possible(value); - - if !value.has_projection_types() { - value.clone() - } else { - value.fold_with(self) - } - } -} - -impl<'a,'b,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'b,'tcx> { - fn tcx(&self) -> &TyCtxt<'tcx> { - self.selcx.tcx() - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - // We don't want to normalize associated types that occur inside of region - // binders, because they may contain bound regions, and we can't cope with that. - // - // Example: - // - // for<'a> fn(>::A) - // - // Instead of normalizing `>::A` here, we'll - // normalize it when we instantiate those bound regions (which - // should occur eventually). - - let ty = ty.super_fold_with(self); - match ty.sty { - ty::TyProjection(ref data) if !data.has_escaping_regions() => { // (*) - - // (*) This is kind of hacky -- we need to be able to - // handle normalization within binders because - // otherwise we wind up a need to normalize when doing - // trait matching (since you can have a trait - // obligation like `for<'a> T::B : Fn(&'a int)`), but - // we can't normalize with bound regions in scope. So - // far now we just ignore binders but only normalize - // if all bound regions are gone (and then we still - // have to renormalize whenever we instantiate a - // binder). It would be better to normalize in a - // binding-aware fashion. - - let Normalized { value: ty, obligations } = - normalize_projection_type(self.selcx, - data.clone(), - self.cause.clone(), - self.depth); - self.obligations.extend(obligations); - ty - } - - _ => { - ty - } - } - } -} - -#[derive(Clone)] -pub struct Normalized<'tcx,T> { - pub value: T, - pub obligations: Vec>, -} - -pub type NormalizedTy<'tcx> = Normalized<'tcx, Ty<'tcx>>; - -impl<'tcx,T> Normalized<'tcx,T> { - pub fn with(self, value: U) -> Normalized<'tcx,U> { - Normalized { value: value, obligations: self.obligations } - } -} - -/// The guts of `normalize`: normalize a specific projection like `::Item`. The result is always a type (and possibly -/// additional obligations). If ambiguity arises, which implies that -/// there are unresolved type variables in the projection, we will -/// substitute a fresh type variable `$X` and generate a new -/// obligation `::Item == $X` for later. -pub fn normalize_projection_type<'a,'b,'tcx>( - selcx: &'a mut SelectionContext<'b,'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize) - -> NormalizedTy<'tcx> -{ - opt_normalize_projection_type(selcx, projection_ty.clone(), cause.clone(), depth) - .unwrap_or_else(move || { - // if we bottom out in ambiguity, create a type variable - // and a deferred predicate to resolve this when more type - // information is available. - - let ty_var = selcx.infcx().next_ty_var(); - let projection = ty::Binder(ty::ProjectionPredicate { - projection_ty: projection_ty, - ty: ty_var - }); - let obligation = Obligation::with_depth( - cause, depth + 1, projection.to_predicate()); - Normalized { - value: ty_var, - obligations: vec!(obligation) - } - }) -} - -/// The guts of `normalize`: normalize a specific projection like `::Item`. The result is always a type (and possibly -/// additional obligations). Returns `None` in the case of ambiguity, -/// which indicates that there are unbound type variables. -fn opt_normalize_projection_type<'a,'b,'tcx>( - selcx: &'a mut SelectionContext<'b,'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize) - -> Option> -{ - debug!("normalize_projection_type(\ - projection_ty={:?}, \ - depth={})", - projection_ty, - depth); - - let obligation = Obligation::with_depth(cause.clone(), depth, projection_ty.clone()); - match project_type(selcx, &obligation) { - Ok(ProjectedTy::Progress(projected_ty, mut obligations)) => { - // if projection succeeded, then what we get out of this - // is also non-normalized (consider: it was derived from - // an impl, where-clause etc) and hence we must - // re-normalize it - - debug!("normalize_projection_type: projected_ty={:?} depth={} obligations={:?}", - projected_ty, - depth, - obligations); - - if projected_ty.has_projection_types() { - let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, depth+1); - let normalized_ty = normalizer.fold(&projected_ty); - - debug!("normalize_projection_type: normalized_ty={:?} depth={}", - normalized_ty, - depth); - - obligations.extend(normalizer.obligations); - Some(Normalized { - value: normalized_ty, - obligations: obligations, - }) - } else { - Some(Normalized { - value: projected_ty, - obligations: obligations, - }) - } - } - Ok(ProjectedTy::NoProgress(projected_ty)) => { - debug!("normalize_projection_type: projected_ty={:?} no progress", - projected_ty); - Some(Normalized { - value: projected_ty, - obligations: vec!() - }) - } - Err(ProjectionTyError::TooManyCandidates) => { - debug!("normalize_projection_type: too many candidates"); - None - } - Err(ProjectionTyError::TraitSelectionError(_)) => { - debug!("normalize_projection_type: ERROR"); - // if we got an error processing the `T as Trait` part, - // just return `ty::err` but add the obligation `T : - // Trait`, which when processed will cause the error to be - // reported later - - Some(normalize_to_error(selcx, projection_ty, cause, depth)) - } - } -} - -/// If we are projecting `::Item`, but `T: Trait` does not -/// hold. In various error cases, we cannot generate a valid -/// normalized projection. Therefore, we create an inference variable -/// return an associated obligation that, when fulfilled, will lead to -/// an error. -/// -/// Note that we used to return `TyError` here, but that was quite -/// dubious -- the premise was that an error would *eventually* be -/// reported, when the obligation was processed. But in general once -/// you see a `TyError` you are supposed to be able to assume that an -/// error *has been* reported, so that you can take whatever heuristic -/// paths you want to take. To make things worse, it was possible for -/// cycles to arise, where you basically had a setup like ` -/// as Trait>::Foo == $0`. Here, normalizing ` as -/// Trait>::Foo> to `[type error]` would lead to an obligation of -/// ` as Trait>::Foo`. We are supposed to report -/// an error for this obligation, but we legitimately should not, -/// because it contains `[type error]`. Yuck! (See issue #29857 for -/// one case where this arose.) -fn normalize_to_error<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize) - -> NormalizedTy<'tcx> -{ - let trait_ref = projection_ty.trait_ref.to_poly_trait_ref(); - let trait_obligation = Obligation { cause: cause, - recursion_depth: depth, - predicate: trait_ref.to_predicate() }; - let new_value = selcx.infcx().next_ty_var(); - Normalized { - value: new_value, - obligations: vec!(trait_obligation) - } -} - -enum ProjectedTy<'tcx> { - Progress(Ty<'tcx>, Vec>), - NoProgress(Ty<'tcx>), -} - -/// Compute the result of a projection type (if we can). -fn project_type<'cx,'tcx>( - selcx: &mut SelectionContext<'cx,'tcx>, - obligation: &ProjectionTyObligation<'tcx>) - -> Result, ProjectionTyError<'tcx>> -{ - debug!("project(obligation={:?})", - obligation); - - let recursion_limit = selcx.tcx().sess.recursion_limit.get(); - if obligation.recursion_depth >= recursion_limit { - debug!("project: overflow!"); - report_overflow_error(selcx.infcx(), &obligation, true); - } - - let obligation_trait_ref = - selcx.infcx().resolve_type_vars_if_possible(&obligation.predicate.trait_ref); - - debug!("project: obligation_trait_ref={:?}", obligation_trait_ref); - - if obligation_trait_ref.references_error() { - return Ok(ProjectedTy::Progress(selcx.tcx().types.err, vec!())); - } - - let mut candidates = ProjectionTyCandidateSet { - vec: Vec::new(), - ambiguous: false, - }; - - assemble_candidates_from_param_env(selcx, - obligation, - &obligation_trait_ref, - &mut candidates); - - assemble_candidates_from_trait_def(selcx, - obligation, - &obligation_trait_ref, - &mut candidates); - - if let Err(e) = assemble_candidates_from_impls(selcx, - obligation, - &obligation_trait_ref, - &mut candidates) { - return Err(ProjectionTyError::TraitSelectionError(e)); - } - - debug!("{} candidates, ambiguous={}", - candidates.vec.len(), - candidates.ambiguous); - - // Inherent ambiguity that prevents us from even enumerating the - // candidates. - if candidates.ambiguous { - return Err(ProjectionTyError::TooManyCandidates); - } - - // Drop duplicates. - // - // Note: `candidates.vec` seems to be on the critical path of the - // compiler. Replacing it with an hash set was also tried, which would - // render the following dedup unnecessary. It led to cleaner code but - // prolonged compiling time of `librustc` from 5m30s to 6m in one test, or - // ~9% performance lost. - if candidates.vec.len() > 1 { - let mut i = 0; - while i < candidates.vec.len() { - let has_dup = (0..i).any(|j| candidates.vec[i] == candidates.vec[j]); - if has_dup { - candidates.vec.swap_remove(i); - } else { - i += 1; - } - } - } - - // Prefer where-clauses. As in select, if there are multiple - // candidates, we prefer where-clause candidates over impls. This - // may seem a bit surprising, since impls are the source of - // "truth" in some sense, but in fact some of the impls that SEEM - // applicable are not, because of nested obligations. Where - // clauses are the safer choice. See the comment on - // `select::SelectionCandidate` and #21974 for more details. - if candidates.vec.len() > 1 { - debug!("retaining param-env candidates only from {:?}", candidates.vec); - candidates.vec.retain(|c| match *c { - ProjectionTyCandidate::ParamEnv(..) => true, - ProjectionTyCandidate::Impl(..) | - ProjectionTyCandidate::Closure(..) | - ProjectionTyCandidate::TraitDef(..) | - ProjectionTyCandidate::FnPointer(..) => false, - }); - debug!("resulting candidate set: {:?}", candidates.vec); - if candidates.vec.len() != 1 { - return Err(ProjectionTyError::TooManyCandidates); - } - } - - assert!(candidates.vec.len() <= 1); - - let possible_candidate = candidates.vec.pop().and_then(|candidate| { - // In Any (i.e. trans) mode, all projections succeed; - // otherwise, we need to be sensitive to `default` and - // specialization. - if !selcx.projection_mode().is_any() { - if let ProjectionTyCandidate::Impl(ref impl_data) = candidate { - if let Some(node_item) = assoc_ty_def(selcx, - impl_data.impl_def_id, - obligation.predicate.item_name) { - if node_item.node.is_from_trait() { - if node_item.item.ty.is_some() { - // If the associated type has a default from the - // trait, that should be considered `default` and - // hence not projected. - // - // Note, however, that we allow a projection from - // the trait specifically in the case that the trait - // does *not* give a default. This is purely to - // avoid spurious errors: the situation can only - // arise when *no* impl in the specialization chain - // has provided a definition for the type. When we - // confirm the candidate, we'll turn the projection - // into a TyError, since the actual error will be - // reported in `check_impl_items_against_trait`. - return None; - } - } else if node_item.item.defaultness.is_default() { - return None; - } - } else { - // Normally this situation could only arise througha - // compiler bug, but at coherence-checking time we only look - // at the topmost impl (we don't even consider the trait - // itself) for the definition -- so we can fail to find a - // definition of the type even if it exists. - - // For now, we just unconditionally ICE, because otherwise, - // examples like the following will succeed: - // - // ``` - // trait Assoc { - // type Output; - // } - // - // impl Assoc for T { - // default type Output = bool; - // } - // - // impl Assoc for u8 {} - // impl Assoc for u16 {} - // - // trait Foo {} - // impl Foo for ::Output {} - // impl Foo for ::Output {} - // return None; - // } - // ``` - // - // The essential problem here is that the projection fails, - // leaving two unnormalized types, which appear not to unify - // -- so the overlap check succeeds, when it should fail. - selcx.tcx().sess.bug("Tried to project an inherited associated type during \ - coherence checking, which is currently not supported."); - } - } - } - Some(candidate) - }); - - match possible_candidate { - Some(candidate) => { - let (ty, obligations) = confirm_candidate(selcx, obligation, candidate); - Ok(ProjectedTy::Progress(ty, obligations)) - } - None => { - Ok(ProjectedTy::NoProgress(selcx.tcx().mk_projection( - obligation.predicate.trait_ref.clone(), - obligation.predicate.item_name))) - } - } -} - -/// The first thing we have to do is scan through the parameter -/// environment to see whether there are any projection predicates -/// there that can answer this question. -fn assemble_candidates_from_param_env<'cx,'tcx>( - selcx: &mut SelectionContext<'cx,'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, - candidate_set: &mut ProjectionTyCandidateSet<'tcx>) -{ - debug!("assemble_candidates_from_param_env(..)"); - let env_predicates = selcx.param_env().caller_bounds.iter().cloned(); - assemble_candidates_from_predicates(selcx, - obligation, - obligation_trait_ref, - candidate_set, - ProjectionTyCandidate::ParamEnv, - env_predicates); -} - -/// In the case of a nested projection like <::FooT as Bar>::BarT, we may find -/// that the definition of `Foo` has some clues: -/// -/// ``` -/// trait Foo { -/// type FooT : Bar -/// } -/// ``` -/// -/// Here, for example, we could conclude that the result is `i32`. -fn assemble_candidates_from_trait_def<'cx,'tcx>( - selcx: &mut SelectionContext<'cx,'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, - candidate_set: &mut ProjectionTyCandidateSet<'tcx>) -{ - debug!("assemble_candidates_from_trait_def(..)"); - - // Check whether the self-type is itself a projection. - let trait_ref = match obligation_trait_ref.self_ty().sty { - ty::TyProjection(ref data) => data.trait_ref.clone(), - ty::TyInfer(ty::TyVar(_)) => { - // If the self-type is an inference variable, then it MAY wind up - // being a projected type, so induce an ambiguity. - candidate_set.ambiguous = true; - return; - } - _ => { return; } - }; - - // If so, extract what we know from the trait and try to come up with a good answer. - let trait_predicates = selcx.tcx().lookup_predicates(trait_ref.def_id); - let bounds = trait_predicates.instantiate(selcx.tcx(), trait_ref.substs); - let bounds = elaborate_predicates(selcx.tcx(), bounds.predicates.into_vec()); - assemble_candidates_from_predicates(selcx, - obligation, - obligation_trait_ref, - candidate_set, - ProjectionTyCandidate::TraitDef, - bounds) -} - -fn assemble_candidates_from_predicates<'cx,'tcx,I>( - selcx: &mut SelectionContext<'cx,'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, - candidate_set: &mut ProjectionTyCandidateSet<'tcx>, - ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>, - env_predicates: I) - where I: Iterator> -{ - debug!("assemble_candidates_from_predicates(obligation={:?})", - obligation); - let infcx = selcx.infcx(); - for predicate in env_predicates { - debug!("assemble_candidates_from_predicates: predicate={:?}", - predicate); - match predicate { - ty::Predicate::Projection(ref data) => { - let same_name = data.item_name() == obligation.predicate.item_name; - - let is_match = same_name && infcx.probe(|_| { - let origin = TypeOrigin::Misc(obligation.cause.span); - let data_poly_trait_ref = - data.to_poly_trait_ref(); - let obligation_poly_trait_ref = - obligation_trait_ref.to_poly_trait_ref(); - infcx.sub_poly_trait_refs(false, - origin, - data_poly_trait_ref, - obligation_poly_trait_ref).is_ok() - }); - - debug!("assemble_candidates_from_predicates: candidate={:?} \ - is_match={} same_name={}", - data, is_match, same_name); - - if is_match { - candidate_set.vec.push(ctor(data.clone())); - } - } - _ => { } - } - } -} - -fn assemble_candidates_from_object_type<'cx,'tcx>( - selcx: &mut SelectionContext<'cx,'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, - candidate_set: &mut ProjectionTyCandidateSet<'tcx>) -{ - let self_ty = obligation_trait_ref.self_ty(); - let object_ty = selcx.infcx().shallow_resolve(self_ty); - debug!("assemble_candidates_from_object_type(object_ty={:?})", - object_ty); - let data = match object_ty.sty { - ty::TyTrait(ref data) => data, - _ => { - selcx.tcx().sess.span_bug( - obligation.cause.span, - &format!("assemble_candidates_from_object_type called with non-object: {:?}", - object_ty)); - } - }; - let projection_bounds = data.projection_bounds_with_self_ty(selcx.tcx(), object_ty); - let env_predicates = projection_bounds.iter() - .map(|p| p.to_predicate()) - .collect(); - let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates); - assemble_candidates_from_predicates(selcx, - obligation, - obligation_trait_ref, - candidate_set, - ProjectionTyCandidate::ParamEnv, - env_predicates) -} - -fn assemble_candidates_from_impls<'cx,'tcx>( - selcx: &mut SelectionContext<'cx,'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, - candidate_set: &mut ProjectionTyCandidateSet<'tcx>) - -> Result<(), SelectionError<'tcx>> -{ - // If we are resolving `>::Item == Type`, - // start out by selecting the predicate `T as TraitRef<...>`: - let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); - let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate()); - let vtable = match selcx.select(&trait_obligation) { - Ok(Some(vtable)) => vtable, - Ok(None) => { - candidate_set.ambiguous = true; - return Ok(()); - } - Err(e) => { - debug!("assemble_candidates_from_impls: selection error {:?}", - e); - return Err(e); - } - }; - - match vtable { - super::VtableImpl(data) => { - debug!("assemble_candidates_from_impls: impl candidate {:?}", - data); - - candidate_set.vec.push( - ProjectionTyCandidate::Impl(data)); - } - super::VtableObject(_) => { - assemble_candidates_from_object_type( - selcx, obligation, obligation_trait_ref, candidate_set); - } - super::VtableClosure(data) => { - candidate_set.vec.push( - ProjectionTyCandidate::Closure(data)); - } - super::VtableFnPointer(fn_type) => { - candidate_set.vec.push( - ProjectionTyCandidate::FnPointer(fn_type)); - } - super::VtableParam(..) => { - // This case tell us nothing about the value of an - // associated type. Consider: - // - // ``` - // trait SomeTrait { type Foo; } - // fn foo(...) { } - // ``` - // - // If the user writes `::Foo`, then the `T - // : SomeTrait` binding does not help us decide what the - // type `Foo` is (at least, not more specifically than - // what we already knew). - // - // But wait, you say! What about an example like this: - // - // ``` - // fn bar>(...) { ... } - // ``` - // - // Doesn't the `T : Sometrait` predicate help - // resolve `T::Foo`? And of course it does, but in fact - // that single predicate is desugared into two predicates - // in the compiler: a trait predicate (`T : SomeTrait`) and a - // projection. And the projection where clause is handled - // in `assemble_candidates_from_param_env`. - } - super::VtableDefaultImpl(..) | - super::VtableBuiltin(..) => { - // These traits have no associated types. - selcx.tcx().sess.span_bug( - obligation.cause.span, - &format!("Cannot project an associated type from `{:?}`", - vtable)); - } - } - - Ok(()) -} - -fn confirm_candidate<'cx,'tcx>( - selcx: &mut SelectionContext<'cx,'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - candidate: ProjectionTyCandidate<'tcx>) - -> (Ty<'tcx>, Vec>) -{ - debug!("confirm_candidate(candidate={:?}, obligation={:?})", - candidate, - obligation); - - match candidate { - ProjectionTyCandidate::ParamEnv(poly_projection) | - ProjectionTyCandidate::TraitDef(poly_projection) => { - confirm_param_env_candidate(selcx, obligation, poly_projection) - } - - ProjectionTyCandidate::Impl(impl_vtable) => { - confirm_impl_candidate(selcx, obligation, impl_vtable) - } - - ProjectionTyCandidate::Closure(closure_vtable) => { - confirm_closure_candidate(selcx, obligation, closure_vtable) - } - - ProjectionTyCandidate::FnPointer(fn_type) => { - confirm_fn_pointer_candidate(selcx, obligation, fn_type) - } - } -} - -fn confirm_fn_pointer_candidate<'cx,'tcx>( - selcx: &mut SelectionContext<'cx,'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - fn_type: Ty<'tcx>) - -> (Ty<'tcx>, Vec>) -{ - let fn_type = selcx.infcx().shallow_resolve(fn_type); - let sig = fn_type.fn_sig(); - confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes) -} - -fn confirm_closure_candidate<'cx,'tcx>( - selcx: &mut SelectionContext<'cx,'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - vtable: VtableClosureData<'tcx, PredicateObligation<'tcx>>) - -> (Ty<'tcx>, Vec>) -{ - let closure_typer = selcx.closure_typer(); - let closure_type = closure_typer.closure_type(vtable.closure_def_id, &vtable.substs); - let Normalized { - value: closure_type, - mut obligations - } = normalize_with_depth(selcx, - obligation.cause.clone(), - obligation.recursion_depth+1, - &closure_type); - let (ty, mut cc_obligations) = confirm_callable_candidate(selcx, - obligation, - &closure_type.sig, - util::TupleArgumentsFlag::No); - obligations.append(&mut cc_obligations); - (ty, obligations) -} - -fn confirm_callable_candidate<'cx,'tcx>( - selcx: &mut SelectionContext<'cx,'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - fn_sig: &ty::PolyFnSig<'tcx>, - flag: util::TupleArgumentsFlag) - -> (Ty<'tcx>, Vec>) -{ - let tcx = selcx.tcx(); - - debug!("confirm_callable_candidate({:?},{:?})", - obligation, - fn_sig); - - // the `Output` associated type is declared on `FnOnce` - let fn_once_def_id = tcx.lang_items.fn_once_trait().unwrap(); - - // Note: we unwrap the binder here but re-create it below (1) - let ty::Binder((trait_ref, ret_type)) = - util::closure_trait_ref_and_return_type(tcx, - fn_once_def_id, - obligation.predicate.trait_ref.self_ty(), - fn_sig, - flag); - - let predicate = ty::Binder(ty::ProjectionPredicate { // (1) recreate binder here - projection_ty: ty::ProjectionTy { - trait_ref: trait_ref, - item_name: token::intern(FN_OUTPUT_NAME), - }, - ty: ret_type - }); - - confirm_param_env_candidate(selcx, obligation, predicate) -} - -fn confirm_param_env_candidate<'cx,'tcx>( - selcx: &mut SelectionContext<'cx,'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - poly_projection: ty::PolyProjectionPredicate<'tcx>) - -> (Ty<'tcx>, Vec>) -{ - let infcx = selcx.infcx(); - - let projection = - infcx.replace_late_bound_regions_with_fresh_var( - obligation.cause.span, - infer::LateBoundRegionConversionTime::HigherRankedType, - &poly_projection).0; - - assert_eq!(projection.projection_ty.item_name, - obligation.predicate.item_name); - - let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); - match infcx.eq_trait_refs(false, - origin, - obligation.predicate.trait_ref.clone(), - projection.projection_ty.trait_ref.clone()) { - Ok(()) => { } - Err(e) => { - selcx.tcx().sess.span_bug( - obligation.cause.span, - &format!("Failed to unify `{:?}` and `{:?}` in projection: {}", - obligation, - projection, - e)); - } - } - - (projection.ty, vec!()) -} - -fn confirm_impl_candidate<'cx,'tcx>( - selcx: &mut SelectionContext<'cx,'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - impl_vtable: VtableImplData<'tcx, PredicateObligation<'tcx>>) - -> (Ty<'tcx>, Vec>) -{ - let VtableImplData { substs, nested, impl_def_id } = impl_vtable; - - let tcx = selcx.tcx(); - let trait_ref = obligation.predicate.trait_ref; - let assoc_ty = assoc_ty_def(selcx, impl_def_id, obligation.predicate.item_name); - - match assoc_ty { - Some(node_item) => { - let ty = node_item.item.ty.unwrap_or_else(|| { - // This means that the impl is missing a definition for the - // associated type. This error will be reported by the type - // checker method `check_impl_items_against_trait`, so here we - // just return TyError. - debug!("confirm_impl_candidate: no associated type {:?} for {:?}", - node_item.item.name, - obligation.predicate.trait_ref); - tcx.types.err - }); - let substs = translate_substs(selcx.infcx(), impl_def_id, substs, node_item.node); - (ty.subst(tcx, substs), nested) - } - None => { - tcx.sess.span_bug(obligation.cause.span, - &format!("No associated type for {:?}", trait_ref)); - } - } -} - -/// Locate the definition of an associated type in the specialization hierarchy, -/// starting from the given impl. -/// -/// Based on the "projection mode", this lookup may in fact only examine the -/// topmost impl. See the comments for `ProjectionMode` for more details. -fn assoc_ty_def<'cx, 'tcx>(selcx: &SelectionContext<'cx, 'tcx>, - impl_def_id: DefId, - assoc_ty_name: ast::Name) - -> Option>>> -{ - let trait_def_id = selcx.tcx().impl_trait_ref(impl_def_id).unwrap().def_id; - - if selcx.projection_mode().is_topmost() { - let impl_node = specialization_graph::Node::Impl(impl_def_id); - for item in impl_node.items(selcx.tcx()) { - if let ty::TypeTraitItem(assoc_ty) = item { - if assoc_ty.name == assoc_ty_name { - return Some(specialization_graph::NodeItem { - node: specialization_graph::Node::Impl(impl_def_id), - item: assoc_ty, - }); - } - } - } - None - } else { - selcx.tcx().lookup_trait_def(trait_def_id) - .ancestors(impl_def_id) - .type_defs(selcx.tcx(), assoc_ty_name) - .next() - } -} diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs deleted file mode 100644 index 050468809a5..00000000000 --- a/src/librustc/middle/traits/select.rs +++ /dev/null @@ -1,3049 +0,0 @@ -// Copyright 2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! See `README.md` for high-level documentation - -pub use self::MethodMatchResult::*; -pub use self::MethodMatchedData::*; -use self::SelectionCandidate::*; -use self::BuiltinBoundConditions::*; -use self::EvaluationResult::*; - -use super::coherence; -use super::DerivedObligationCause; -use super::project; -use super::project::{normalize_with_depth, Normalized}; -use super::{PredicateObligation, TraitObligation, ObligationCause}; -use super::report_overflow_error; -use super::{ObligationCauseCode, BuiltinDerivedObligation, ImplDerivedObligation}; -use super::{SelectionError, Unimplemented, OutputTypeParameterMismatch}; -use super::{ObjectCastObligation, Obligation}; -use super::ProjectionMode; -use super::TraitNotObjectSafe; -use super::Selection; -use super::SelectionResult; -use super::{VtableBuiltin, VtableImpl, VtableParam, VtableClosure, - VtableFnPointer, VtableObject, VtableDefaultImpl}; -use super::{VtableImplData, VtableObjectData, VtableBuiltinData, - VtableClosureData, VtableDefaultImplData}; -use super::object_safety; -use super::util; - -use middle::def_id::DefId; -use middle::infer; -use middle::infer::{InferCtxt, TypeFreshener, TypeOrigin}; -use middle::ty::subst::{Subst, Substs, TypeSpace}; -use middle::ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; -use middle::traits; -use middle::ty::fast_reject; -use middle::ty::relate::TypeRelation; - -use std::cell::RefCell; -use std::fmt; -use std::rc::Rc; -use syntax::abi::Abi; -use rustc_front::hir; -use util::common::ErrorReported; -use util::nodemap::FnvHashMap; - -pub struct SelectionContext<'cx, 'tcx:'cx> { - infcx: &'cx InferCtxt<'cx, 'tcx>, - - /// Freshener used specifically for skolemizing entries on the - /// obligation stack. This ensures that all entries on the stack - /// at one time will have the same set of skolemized entries, - /// which is important for checking for trait bounds that - /// recursively require themselves. - freshener: TypeFreshener<'cx, 'tcx>, - - /// If true, indicates that the evaluation should be conservative - /// and consider the possibility of types outside this crate. - /// This comes up primarily when resolving ambiguity. Imagine - /// there is some trait reference `$0 : Bar` where `$0` is an - /// inference variable. If `intercrate` is true, then we can never - /// say for sure that this reference is not implemented, even if - /// there are *no impls at all for `Bar`*, because `$0` could be - /// bound to some type that in a downstream crate that implements - /// `Bar`. This is the suitable mode for coherence. Elsewhere, - /// though, we set this to false, because we are only interested - /// in types that the user could actually have written --- in - /// other words, we consider `$0 : Bar` to be unimplemented if - /// there is no type that the user could *actually name* that - /// would satisfy it. This avoids crippling inference, basically. - intercrate: bool, -} - -// A stack that walks back up the stack frame. -struct TraitObligationStack<'prev, 'tcx: 'prev> { - obligation: &'prev TraitObligation<'tcx>, - - /// Trait ref from `obligation` but skolemized with the - /// selection-context's freshener. Used to check for recursion. - fresh_trait_ref: ty::PolyTraitRef<'tcx>, - - previous: TraitObligationStackList<'prev, 'tcx>, -} - -#[derive(Clone)] -pub struct SelectionCache<'tcx> { - hashmap: RefCell, - SelectionResult<'tcx, SelectionCandidate<'tcx>>>>, -} - -pub enum MethodMatchResult { - MethodMatched(MethodMatchedData), - MethodAmbiguous(/* list of impls that could apply */ Vec), - MethodDidNotMatch, -} - -#[derive(Copy, Clone, Debug)] -pub enum MethodMatchedData { - // In the case of a precise match, we don't really need to store - // how the match was found. So don't. - PreciseMethodMatch, - - // In the case of a coercion, we need to know the precise impl so - // that we can determine the type to which things were coerced. - CoerciveMethodMatch(/* impl we matched */ DefId) -} - -/// The selection process begins by considering all impls, where -/// clauses, and so forth that might resolve an obligation. Sometimes -/// we'll be able to say definitively that (e.g.) an impl does not -/// apply to the obligation: perhaps it is defined for `usize` but the -/// obligation is for `int`. In that case, we drop the impl out of the -/// list. But the other cases are considered *candidates*. -/// -/// For selection to succeed, there must be exactly one matching -/// candidate. If the obligation is fully known, this is guaranteed -/// by coherence. However, if the obligation contains type parameters -/// or variables, there may be multiple such impls. -/// -/// It is not a real problem if multiple matching impls exist because -/// of type variables - it just means the obligation isn't sufficiently -/// elaborated. In that case we report an ambiguity, and the caller can -/// try again after more type information has been gathered or report a -/// "type annotations required" error. -/// -/// However, with type parameters, this can be a real problem - type -/// parameters don't unify with regular types, but they *can* unify -/// with variables from blanket impls, and (unless we know its bounds -/// will always be satisfied) picking the blanket impl will be wrong -/// for at least *some* substitutions. To make this concrete, if we have -/// -/// trait AsDebug { type Out : fmt::Debug; fn debug(self) -> Self::Out; } -/// impl AsDebug for T { -/// type Out = T; -/// fn debug(self) -> fmt::Debug { self } -/// } -/// fn foo(t: T) { println!("{:?}", ::debug(t)); } -/// -/// we can't just use the impl to resolve the obligation -/// - a type from another crate (that doesn't implement fmt::Debug) could -/// implement AsDebug. -/// -/// Because where-clauses match the type exactly, multiple clauses can -/// only match if there are unresolved variables, and we can mostly just -/// report this ambiguity in that case. This is still a problem - we can't -/// *do anything* with ambiguities that involve only regions. This is issue -/// #21974. -/// -/// If a single where-clause matches and there are no inference -/// variables left, then it definitely matches and we can just select -/// it. -/// -/// In fact, we even select the where-clause when the obligation contains -/// inference variables. The can lead to inference making "leaps of logic", -/// for example in this situation: -/// -/// pub trait Foo { fn foo(&self) -> T; } -/// impl Foo<()> for T { fn foo(&self) { } } -/// impl Foo for bool { fn foo(&self) -> bool { *self } } -/// -/// pub fn foo(t: T) where T: Foo { -/// println!("{:?}", >::foo(&t)); -/// } -/// fn main() { foo(false); } -/// -/// Here the obligation > can be matched by both the blanket -/// impl and the where-clause. We select the where-clause and unify $0=bool, -/// so the program prints "false". However, if the where-clause is omitted, -/// the blanket impl is selected, we unify $0=(), and the program prints -/// "()". -/// -/// Exactly the same issues apply to projection and object candidates, except -/// that we can have both a projection candidate and a where-clause candidate -/// for the same obligation. In that case either would do (except that -/// different "leaps of logic" would occur if inference variables are -/// present), and we just pick the where-clause. This is, for example, -/// required for associated types to work in default impls, as the bounds -/// are visible both as projection bounds and as where-clauses from the -/// parameter environment. -#[derive(PartialEq,Eq,Debug,Clone)] -enum SelectionCandidate<'tcx> { - BuiltinCandidate(ty::BuiltinBound), - ParamCandidate(ty::PolyTraitRef<'tcx>), - ImplCandidate(DefId), - DefaultImplCandidate(DefId), - DefaultImplObjectCandidate(DefId), - - /// This is a trait matching with a projected type as `Self`, and - /// we found an applicable bound in the trait definition. - ProjectionCandidate, - - /// Implementation of a `Fn`-family trait by one of the - /// anonymous types generated for a `||` expression. - ClosureCandidate(/* closure */ DefId, &'tcx ty::ClosureSubsts<'tcx>), - - /// Implementation of a `Fn`-family trait by one of the anonymous - /// types generated for a fn pointer type (e.g., `fn(int)->int`) - FnPointerCandidate, - - ObjectCandidate, - - BuiltinObjectCandidate, - - BuiltinUnsizeCandidate, -} - -struct SelectionCandidateSet<'tcx> { - // a list of candidates that definitely apply to the current - // obligation (meaning: types unify). - vec: Vec>, - - // if this is true, then there were candidates that might or might - // not have applied, but we couldn't tell. This occurs when some - // of the input types are type variables, in which case there are - // various "builtin" rules that might or might not trigger. - ambiguous: bool, -} - -#[derive(PartialEq,Eq,Debug,Clone)] -struct EvaluatedCandidate<'tcx> { - candidate: SelectionCandidate<'tcx>, - evaluation: EvaluationResult, -} - -enum BuiltinBoundConditions<'tcx> { - If(ty::Binder>>), - ParameterBuiltin, - AmbiguousBuiltin -} - -#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] -/// The result of trait evaluation. The order is important -/// here as the evaluation of a list is the maximum of the -/// evaluations. -enum EvaluationResult { - /// Evaluation successful - EvaluatedToOk, - /// Evaluation failed because of recursion - treated as ambiguous - EvaluatedToUnknown, - /// Evaluation is known to be ambiguous - EvaluatedToAmbig, - /// Evaluation failed - EvaluatedToErr, -} - -#[derive(Clone)] -pub struct EvaluationCache<'tcx> { - hashmap: RefCell, EvaluationResult>> -} - -impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { - pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> { - SelectionContext { - infcx: infcx, - freshener: infcx.freshener(), - intercrate: false, - } - } - - pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> { - SelectionContext { - infcx: infcx, - freshener: infcx.freshener(), - intercrate: true, - } - } - - pub fn infcx(&self) -> &'cx InferCtxt<'cx, 'tcx> { - self.infcx - } - - pub fn tcx(&self) -> &'cx TyCtxt<'tcx> { - self.infcx.tcx - } - - pub fn param_env(&self) -> &'cx ty::ParameterEnvironment<'cx, 'tcx> { - self.infcx.param_env() - } - - pub fn closure_typer(&self) -> &'cx InferCtxt<'cx, 'tcx> { - self.infcx - } - - pub fn projection_mode(&self) -> ProjectionMode { - self.infcx.projection_mode() - } - - /////////////////////////////////////////////////////////////////////////// - // Selection - // - // The selection phase tries to identify *how* an obligation will - // be resolved. For example, it will identify which impl or - // parameter bound is to be used. The process can be inconclusive - // if the self type in the obligation is not fully inferred. Selection - // can result in an error in one of two ways: - // - // 1. If no applicable impl or parameter bound can be found. - // 2. If the output type parameters in the obligation do not match - // those specified by the impl/bound. For example, if the obligation - // is `Vec:Iterable`, but the impl specifies - // `impl Iterable for Vec`, than an error would result. - - /// Attempts to satisfy the obligation. If successful, this will affect the surrounding - /// type environment by performing unification. - pub fn select(&mut self, obligation: &TraitObligation<'tcx>) - -> SelectionResult<'tcx, Selection<'tcx>> { - debug!("select({:?})", obligation); - assert!(!obligation.predicate.has_escaping_regions()); - - let dep_node = obligation.predicate.dep_node(); - let _task = self.tcx().dep_graph.in_task(dep_node); - - let stack = self.push_stack(TraitObligationStackList::empty(), obligation); - match self.candidate_from_obligation(&stack)? { - None => { - self.consider_unification_despite_ambiguity(obligation); - Ok(None) - } - Some(candidate) => Ok(Some(self.confirm_candidate(obligation, candidate)?)), - } - } - - /// In the particular case of unboxed closure obligations, we can - /// sometimes do some amount of unification for the - /// argument/return types even though we can't yet fully match obligation. - /// The particular case we are interesting in is an obligation of the form: - /// - /// C : FnFoo - /// - /// where `C` is an unboxed closure type and `FnFoo` is one of the - /// `Fn` traits. Because we know that users cannot write impls for closure types - /// themselves, the only way that `C : FnFoo` can fail to match is under two - /// conditions: - /// - /// 1. The closure kind for `C` is not yet known, because inference isn't complete. - /// 2. The closure kind for `C` *is* known, but doesn't match what is needed. - /// For example, `C` may be a `FnOnce` closure, but a `Fn` closure is needed. - /// - /// In either case, we always know what argument types are - /// expected by `C`, no matter what kind of `Fn` trait it - /// eventually matches. So we can go ahead and unify the argument - /// types, even though the end result is ambiguous. - /// - /// Note that this is safe *even if* the trait would never be - /// matched (case 2 above). After all, in that case, an error will - /// result, so it kind of doesn't matter what we do --- unifying - /// the argument types can only be helpful to the user, because - /// once they patch up the kind of closure that is expected, the - /// argment types won't really change. - fn consider_unification_despite_ambiguity(&mut self, obligation: &TraitObligation<'tcx>) { - // Is this a `C : FnFoo(...)` trait reference for some trait binding `FnFoo`? - match self.tcx().lang_items.fn_trait_kind(obligation.predicate.0.def_id()) { - Some(_) => { } - None => { return; } - } - - // Is the self-type a closure type? We ignore bindings here - // because if it is a closure type, it must be a closure type from - // within this current fn, and hence none of the higher-ranked - // lifetimes can appear inside the self-type. - let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); - let (closure_def_id, substs) = match self_ty.sty { - ty::TyClosure(id, ref substs) => (id, substs), - _ => { return; } - }; - assert!(!substs.has_escaping_regions()); - - // It is OK to call the unnormalized variant here - this is only - // reached for TyClosure: Fn inputs where the closure kind is - // still unknown, which should only occur in typeck where the - // closure type is already normalized. - let closure_trait_ref = self.closure_trait_ref_unnormalized(obligation, - closure_def_id, - substs); - - match self.confirm_poly_trait_refs(obligation.cause.clone(), - obligation.predicate.to_poly_trait_ref(), - closure_trait_ref) { - Ok(()) => { } - Err(_) => { /* Silently ignore errors. */ } - } - } - - /////////////////////////////////////////////////////////////////////////// - // EVALUATION - // - // Tests whether an obligation can be selected or whether an impl - // can be applied to particular types. It skips the "confirmation" - // step and hence completely ignores output type parameters. - // - // The result is "true" if the obligation *may* hold and "false" if - // we can be sure it does not. - - /// Evaluates whether the obligation `obligation` can be satisfied (by any means). - pub fn evaluate_obligation(&mut self, - obligation: &PredicateObligation<'tcx>) - -> bool - { - debug!("evaluate_obligation({:?})", - obligation); - - self.infcx.probe(|_| { - self.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation) - .may_apply() - }) - } - - /// Evaluates whether the obligation `obligation` can be satisfied, - /// and returns `false` if not certain. However, this is not entirely - /// accurate if inference variables are involved. - pub fn evaluate_obligation_conservatively(&mut self, - obligation: &PredicateObligation<'tcx>) - -> bool - { - debug!("evaluate_obligation_conservatively({:?})", - obligation); - - self.infcx.probe(|_| { - self.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation) - == EvaluatedToOk - }) - } - - /// Evaluates the predicates in `predicates` recursively. Note that - /// this applies projections in the predicates, and therefore - /// is run within an inference probe. - fn evaluate_predicates_recursively<'a,'o,I>(&mut self, - stack: TraitObligationStackList<'o, 'tcx>, - predicates: I) - -> EvaluationResult - where I : Iterator>, 'tcx:'a - { - let mut result = EvaluatedToOk; - for obligation in predicates { - let eval = self.evaluate_predicate_recursively(stack, obligation); - debug!("evaluate_predicate_recursively({:?}) = {:?}", - obligation, eval); - match eval { - EvaluatedToErr => { return EvaluatedToErr; } - EvaluatedToAmbig => { result = EvaluatedToAmbig; } - EvaluatedToUnknown => { - if result < EvaluatedToUnknown { - result = EvaluatedToUnknown; - } - } - EvaluatedToOk => { } - } - } - result - } - - fn evaluate_predicate_recursively<'o>(&mut self, - previous_stack: TraitObligationStackList<'o, 'tcx>, - obligation: &PredicateObligation<'tcx>) - -> EvaluationResult - { - debug!("evaluate_predicate_recursively({:?})", - obligation); - - // Check the cache from the tcx of predicates that we know - // have been proven elsewhere. This cache only contains - // predicates that are global in scope and hence unaffected by - // the current environment. - if self.tcx().fulfilled_predicates.borrow().check_duplicate(&obligation.predicate) { - return EvaluatedToOk; - } - - match obligation.predicate { - ty::Predicate::Trait(ref t) => { - assert!(!t.has_escaping_regions()); - let obligation = obligation.with(t.clone()); - self.evaluate_obligation_recursively(previous_stack, &obligation) - } - - ty::Predicate::Equate(ref p) => { - // does this code ever run? - match self.infcx.equality_predicate(obligation.cause.span, p) { - Ok(()) => EvaluatedToOk, - Err(_) => EvaluatedToErr - } - } - - ty::Predicate::WellFormed(ty) => { - match ty::wf::obligations(self.infcx, obligation.cause.body_id, - ty, obligation.cause.span) { - Some(obligations) => - self.evaluate_predicates_recursively(previous_stack, obligations.iter()), - None => - EvaluatedToAmbig, - } - } - - ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => { - // we do not consider region relationships when - // evaluating trait matches - EvaluatedToOk - } - - ty::Predicate::ObjectSafe(trait_def_id) => { - if object_safety::is_object_safe(self.tcx(), trait_def_id) { - EvaluatedToOk - } else { - EvaluatedToErr - } - } - - ty::Predicate::Projection(ref data) => { - let project_obligation = obligation.with(data.clone()); - match project::poly_project_and_unify_type(self, &project_obligation) { - Ok(Some(subobligations)) => { - self.evaluate_predicates_recursively(previous_stack, - subobligations.iter()) - } - Ok(None) => { - EvaluatedToAmbig - } - Err(_) => { - EvaluatedToErr - } - } - } - } - } - - fn evaluate_obligation_recursively<'o>(&mut self, - previous_stack: TraitObligationStackList<'o, 'tcx>, - obligation: &TraitObligation<'tcx>) - -> EvaluationResult - { - debug!("evaluate_obligation_recursively({:?})", - obligation); - - let stack = self.push_stack(previous_stack, obligation); - let fresh_trait_ref = stack.fresh_trait_ref; - if let Some(result) = self.check_evaluation_cache(fresh_trait_ref) { - debug!("CACHE HIT: EVAL({:?})={:?}", - fresh_trait_ref, - result); - return result; - } - - let result = self.evaluate_stack(&stack); - - debug!("CACHE MISS: EVAL({:?})={:?}", - fresh_trait_ref, - result); - self.insert_evaluation_cache(fresh_trait_ref, result); - - result - } - - fn evaluate_stack<'o>(&mut self, - stack: &TraitObligationStack<'o, 'tcx>) - -> EvaluationResult - { - // In intercrate mode, whenever any of the types are unbound, - // there can always be an impl. Even if there are no impls in - // this crate, perhaps the type would be unified with - // something from another crate that does provide an impl. - // - // In intra mode, we must still be conservative. The reason is - // that we want to avoid cycles. Imagine an impl like: - // - // impl Eq for Vec - // - // and a trait reference like `$0 : Eq` where `$0` is an - // unbound variable. When we evaluate this trait-reference, we - // will unify `$0` with `Vec<$1>` (for some fresh variable - // `$1`), on the condition that `$1 : Eq`. We will then wind - // up with many candidates (since that are other `Eq` impls - // that apply) and try to winnow things down. This results in - // a recursive evaluation that `$1 : Eq` -- as you can - // imagine, this is just where we started. To avoid that, we - // check for unbound variables and return an ambiguous (hence possible) - // match if we've seen this trait before. - // - // This suffices to allow chains like `FnMut` implemented in - // terms of `Fn` etc, but we could probably make this more - // precise still. - let input_types = stack.fresh_trait_ref.0.input_types(); - let unbound_input_types = input_types.iter().any(|ty| ty.is_fresh()); - if unbound_input_types && self.intercrate { - debug!("evaluate_stack({:?}) --> unbound argument, intercrate --> ambiguous", - stack.fresh_trait_ref); - return EvaluatedToAmbig; - } - if unbound_input_types && - stack.iter().skip(1).any( - |prev| self.match_fresh_trait_refs(&stack.fresh_trait_ref, - &prev.fresh_trait_ref)) - { - debug!("evaluate_stack({:?}) --> unbound argument, recursive --> giving up", - stack.fresh_trait_ref); - return EvaluatedToUnknown; - } - - // If there is any previous entry on the stack that precisely - // matches this obligation, then we can assume that the - // obligation is satisfied for now (still all other conditions - // must be met of course). One obvious case this comes up is - // marker traits like `Send`. Think of a linked list: - // - // struct List { data: T, next: Option>> { - // - // `Box>` will be `Send` if `T` is `Send` and - // `Option>>` is `Send`, and in turn - // `Option>>` is `Send` if `Box>` is - // `Send`. - // - // Note that we do this comparison using the `fresh_trait_ref` - // fields. Because these have all been skolemized using - // `self.freshener`, we can be sure that (a) this will not - // affect the inferencer state and (b) that if we see two - // skolemized types with the same index, they refer to the - // same unbound type variable. - if - stack.iter() - .skip(1) // skip top-most frame - .any(|prev| stack.fresh_trait_ref == prev.fresh_trait_ref) - { - debug!("evaluate_stack({:?}) --> recursive", - stack.fresh_trait_ref); - return EvaluatedToOk; - } - - match self.candidate_from_obligation(stack) { - Ok(Some(c)) => self.evaluate_candidate(stack, &c), - Ok(None) => EvaluatedToAmbig, - Err(..) => EvaluatedToErr - } - } - - /// Further evaluate `candidate` to decide whether all type parameters match and whether nested - /// obligations are met. Returns true if `candidate` remains viable after this further - /// scrutiny. - fn evaluate_candidate<'o>(&mut self, - stack: &TraitObligationStack<'o, 'tcx>, - candidate: &SelectionCandidate<'tcx>) - -> EvaluationResult - { - debug!("evaluate_candidate: depth={} candidate={:?}", - stack.obligation.recursion_depth, candidate); - let result = self.infcx.probe(|_| { - let candidate = (*candidate).clone(); - match self.confirm_candidate(stack.obligation, candidate) { - Ok(selection) => { - self.evaluate_predicates_recursively( - stack.list(), - selection.nested_obligations().iter()) - } - Err(..) => EvaluatedToErr - } - }); - debug!("evaluate_candidate: depth={} result={:?}", - stack.obligation.recursion_depth, result); - result - } - - fn pick_evaluation_cache(&self) -> &EvaluationCache<'tcx> { - // see comment in `pick_candidate_cache` - if self.intercrate || - !self.param_env().caller_bounds.is_empty() - { - &self.param_env().evaluation_cache - } else - { - &self.tcx().evaluation_cache - } - } - - fn check_evaluation_cache(&self, trait_ref: ty::PolyTraitRef<'tcx>) - -> Option - { - let cache = self.pick_evaluation_cache(); - cache.hashmap.borrow().get(&trait_ref).cloned() - } - - fn insert_evaluation_cache(&mut self, - trait_ref: ty::PolyTraitRef<'tcx>, - result: EvaluationResult) - { - // Avoid caching results that depend on more than just the trait-ref: - // The stack can create EvaluatedToUnknown, and closure signatures - // being yet uninferred can create "spurious" EvaluatedToAmbig - // and EvaluatedToOk. - if result == EvaluatedToUnknown || - ((result == EvaluatedToAmbig || result == EvaluatedToOk) - && trait_ref.has_closure_types()) - { - return; - } - - let cache = self.pick_evaluation_cache(); - cache.hashmap.borrow_mut().insert(trait_ref, result); - } - - /////////////////////////////////////////////////////////////////////////// - // CANDIDATE ASSEMBLY - // - // The selection process begins by examining all in-scope impls, - // caller obligations, and so forth and assembling a list of - // candidates. See `README.md` and the `Candidate` type for more - // details. - - fn candidate_from_obligation<'o>(&mut self, - stack: &TraitObligationStack<'o, 'tcx>) - -> SelectionResult<'tcx, SelectionCandidate<'tcx>> - { - // Watch out for overflow. This intentionally bypasses (and does - // not update) the cache. - let recursion_limit = self.infcx.tcx.sess.recursion_limit.get(); - if stack.obligation.recursion_depth >= recursion_limit { - report_overflow_error(self.infcx(), &stack.obligation, true); - } - - // Check the cache. Note that we skolemize the trait-ref - // separately rather than using `stack.fresh_trait_ref` -- this - // is because we want the unbound variables to be replaced - // with fresh skolemized types starting from index 0. - let cache_fresh_trait_pred = - self.infcx.freshen(stack.obligation.predicate.clone()); - debug!("candidate_from_obligation(cache_fresh_trait_pred={:?}, obligation={:?})", - cache_fresh_trait_pred, - stack); - assert!(!stack.obligation.predicate.has_escaping_regions()); - - match self.check_candidate_cache(&cache_fresh_trait_pred) { - Some(c) => { - debug!("CACHE HIT: SELECT({:?})={:?}", - cache_fresh_trait_pred, - c); - return c; - } - None => { } - } - - // If no match, compute result and insert into cache. - let candidate = self.candidate_from_obligation_no_cache(stack); - - if self.should_update_candidate_cache(&cache_fresh_trait_pred, &candidate) { - debug!("CACHE MISS: SELECT({:?})={:?}", - cache_fresh_trait_pred, candidate); - self.insert_candidate_cache(cache_fresh_trait_pred, candidate.clone()); - } - - candidate - } - - // Treat negative impls as unimplemented - fn filter_negative_impls(&self, candidate: SelectionCandidate<'tcx>) - -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { - if let ImplCandidate(def_id) = candidate { - if self.tcx().trait_impl_polarity(def_id) == Some(hir::ImplPolarity::Negative) { - return Err(Unimplemented) - } - } - Ok(Some(candidate)) - } - - fn candidate_from_obligation_no_cache<'o>(&mut self, - stack: &TraitObligationStack<'o, 'tcx>) - -> SelectionResult<'tcx, SelectionCandidate<'tcx>> - { - if stack.obligation.predicate.references_error() { - // If we encounter a `TyError`, we generally prefer the - // most "optimistic" result in response -- that is, the - // one least likely to report downstream errors. But - // because this routine is shared by coherence and by - // trait selection, there isn't an obvious "right" choice - // here in that respect, so we opt to just return - // ambiguity and let the upstream clients sort it out. - return Ok(None); - } - - if !self.is_knowable(stack) { - debug!("coherence stage: not knowable"); - return Ok(None); - } - - let candidate_set = self.assemble_candidates(stack)?; - - if candidate_set.ambiguous { - debug!("candidate set contains ambig"); - return Ok(None); - } - - let mut candidates = candidate_set.vec; - - debug!("assembled {} candidates for {:?}: {:?}", - candidates.len(), - stack, - candidates); - - // At this point, we know that each of the entries in the - // candidate set is *individually* applicable. Now we have to - // figure out if they contain mutual incompatibilities. This - // frequently arises if we have an unconstrained input type -- - // for example, we are looking for $0:Eq where $0 is some - // unconstrained type variable. In that case, we'll get a - // candidate which assumes $0 == int, one that assumes $0 == - // usize, etc. This spells an ambiguity. - - // If there is more than one candidate, first winnow them down - // by considering extra conditions (nested obligations and so - // forth). We don't winnow if there is exactly one - // candidate. This is a relatively minor distinction but it - // can lead to better inference and error-reporting. An - // example would be if there was an impl: - // - // impl Vec { fn push_clone(...) { ... } } - // - // and we were to see some code `foo.push_clone()` where `boo` - // is a `Vec` and `Bar` does not implement `Clone`. If - // we were to winnow, we'd wind up with zero candidates. - // Instead, we select the right impl now but report `Bar does - // not implement Clone`. - if candidates.len() == 1 { - return self.filter_negative_impls(candidates.pop().unwrap()); - } - - // Winnow, but record the exact outcome of evaluation, which - // is needed for specialization. - let mut candidates: Vec<_> = candidates.into_iter().filter_map(|c| { - let eval = self.evaluate_candidate(stack, &c); - if eval.may_apply() { - Some(EvaluatedCandidate { - candidate: c, - evaluation: eval, - }) - } else { - None - } - }).collect(); - - // If there are STILL multiple candidate, we can further - // reduce the list by dropping duplicates -- including - // resolving specializations. - if candidates.len() > 1 { - let mut i = 0; - while i < candidates.len() { - let is_dup = - (0..candidates.len()) - .filter(|&j| i != j) - .any(|j| self.candidate_should_be_dropped_in_favor_of(&candidates[i], - &candidates[j])); - if is_dup { - debug!("Dropping candidate #{}/{}: {:?}", - i, candidates.len(), candidates[i]); - candidates.swap_remove(i); - } else { - debug!("Retaining candidate #{}/{}: {:?}", - i, candidates.len(), candidates[i]); - i += 1; - } - } - } - - // If there are *STILL* multiple candidates, give up and - // report ambiguity. - if candidates.len() > 1 { - debug!("multiple matches, ambig"); - return Ok(None); - } - - // If there are *NO* candidates, then there are no impls -- - // that we know of, anyway. Note that in the case where there - // are unbound type variables within the obligation, it might - // be the case that you could still satisfy the obligation - // from another crate by instantiating the type variables with - // a type from another crate that does have an impl. This case - // is checked for in `evaluate_stack` (and hence users - // who might care about this case, like coherence, should use - // that function). - if candidates.is_empty() { - return Err(Unimplemented); - } - - // Just one candidate left. - self.filter_negative_impls(candidates.pop().unwrap().candidate) - } - - fn is_knowable<'o>(&mut self, - stack: &TraitObligationStack<'o, 'tcx>) - -> bool - { - debug!("is_knowable(intercrate={})", self.intercrate); - - if !self.intercrate { - return true; - } - - let obligation = &stack.obligation; - let predicate = self.infcx().resolve_type_vars_if_possible(&obligation.predicate); - - // ok to skip binder because of the nature of the - // trait-ref-is-knowable check, which does not care about - // bound regions - let trait_ref = &predicate.skip_binder().trait_ref; - - coherence::trait_ref_is_knowable(self.tcx(), trait_ref) - } - - fn pick_candidate_cache(&self) -> &SelectionCache<'tcx> { - // If there are any where-clauses in scope, then we always use - // a cache local to this particular scope. Otherwise, we - // switch to a global cache. We used to try and draw - // finer-grained distinctions, but that led to a serious of - // annoying and weird bugs like #22019 and #18290. This simple - // rule seems to be pretty clearly safe and also still retains - // a very high hit rate (~95% when compiling rustc). - if !self.param_env().caller_bounds.is_empty() { - return &self.param_env().selection_cache; - } - - // Avoid using the master cache during coherence and just rely - // on the local cache. This effectively disables caching - // during coherence. It is really just a simplification to - // avoid us having to fear that coherence results "pollute" - // the master cache. Since coherence executes pretty quickly, - // it's not worth going to more trouble to increase the - // hit-rate I don't think. - if self.intercrate { - return &self.param_env().selection_cache; - } - - // Otherwise, we can use the global cache. - &self.tcx().selection_cache - } - - fn check_candidate_cache(&mut self, - cache_fresh_trait_pred: &ty::PolyTraitPredicate<'tcx>) - -> Option>> - { - let cache = self.pick_candidate_cache(); - let hashmap = cache.hashmap.borrow(); - hashmap.get(&cache_fresh_trait_pred.0.trait_ref).cloned() - } - - fn insert_candidate_cache(&mut self, - cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, - candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>) - { - let cache = self.pick_candidate_cache(); - let mut hashmap = cache.hashmap.borrow_mut(); - hashmap.insert(cache_fresh_trait_pred.0.trait_ref.clone(), candidate); - } - - fn should_update_candidate_cache(&mut self, - cache_fresh_trait_pred: &ty::PolyTraitPredicate<'tcx>, - candidate: &SelectionResult<'tcx, SelectionCandidate<'tcx>>) - -> bool - { - // In general, it's a good idea to cache results, even - // ambiguous ones, to save us some trouble later. But we have - // to be careful not to cache results that could be - // invalidated later by advances in inference. Normally, this - // is not an issue, because any inference variables whose - // types are not yet bound are "freshened" in the cache key, - // which means that if we later get the same request once that - // type variable IS bound, we'll have a different cache key. - // For example, if we have `Vec<_#0t> : Foo`, and `_#0t` is - // not yet known, we may cache the result as `None`. But if - // later `_#0t` is bound to `Bar`, then when we freshen we'll - // have `Vec : Foo` as the cache key. - // - // HOWEVER, it CAN happen that we get an ambiguity result in - // one particular case around closures where the cache key - // would not change. That is when the precise types of the - // upvars that a closure references have not yet been figured - // out (i.e., because it is not yet known if they are captured - // by ref, and if by ref, what kind of ref). In these cases, - // when matching a builtin bound, we will yield back an - // ambiguous result. But the *cache key* is just the closure type, - // it doesn't capture the state of the upvar computation. - // - // To avoid this trap, just don't cache ambiguous results if - // the self-type contains no inference byproducts (that really - // shouldn't happen in other circumstances anyway, given - // coherence). - - match *candidate { - Ok(Some(_)) | Err(_) => true, - Ok(None) => { - cache_fresh_trait_pred.0.trait_ref.substs.types.has_infer_types() - } - } - } - - fn assemble_candidates<'o>(&mut self, - stack: &TraitObligationStack<'o, 'tcx>) - -> Result, SelectionError<'tcx>> - { - let TraitObligationStack { obligation, .. } = *stack; - let ref obligation = Obligation { - cause: obligation.cause.clone(), - recursion_depth: obligation.recursion_depth, - predicate: self.infcx().resolve_type_vars_if_possible(&obligation.predicate) - }; - - if obligation.predicate.skip_binder().self_ty().is_ty_var() { - // FIXME(#20297): Self is a type variable (e.g. `_: AsRef`). - // - // This is somewhat problematic, as the current scheme can't really - // handle it turning to be a projection. This does end up as truly - // ambiguous in most cases anyway. - // - // Until this is fixed, take the fast path out - this also improves - // performance by preventing assemble_candidates_from_impls from - // matching every impl for this trait. - return Ok(SelectionCandidateSet { vec: vec![], ambiguous: true }); - } - - let mut candidates = SelectionCandidateSet { - vec: Vec::new(), - ambiguous: false - }; - - // Other bounds. Consider both in-scope bounds from fn decl - // and applicable impls. There is a certain set of precedence rules here. - - match self.tcx().lang_items.to_builtin_kind(obligation.predicate.def_id()) { - Some(ty::BoundCopy) => { - debug!("obligation self ty is {:?}", - obligation.predicate.0.self_ty()); - - // User-defined copy impls are permitted, but only for - // structs and enums. - self.assemble_candidates_from_impls(obligation, &mut candidates)?; - - // For other types, we'll use the builtin rules. - self.assemble_builtin_bound_candidates(ty::BoundCopy, - obligation, - &mut candidates)?; - } - Some(bound @ ty::BoundSized) => { - // Sized is never implementable by end-users, it is - // always automatically computed. - self.assemble_builtin_bound_candidates(bound, - obligation, - &mut candidates)?; - } - - None if self.tcx().lang_items.unsize_trait() == - Some(obligation.predicate.def_id()) => { - self.assemble_candidates_for_unsizing(obligation, &mut candidates); - } - - Some(ty::BoundSend) | - Some(ty::BoundSync) | - None => { - self.assemble_closure_candidates(obligation, &mut candidates)?; - self.assemble_fn_pointer_candidates(obligation, &mut candidates)?; - self.assemble_candidates_from_impls(obligation, &mut candidates)?; - self.assemble_candidates_from_object_ty(obligation, &mut candidates); - } - } - - self.assemble_candidates_from_projected_tys(obligation, &mut candidates); - self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?; - // Default implementations have lower priority, so we only - // consider triggering a default if there is no other impl that can apply. - if candidates.vec.is_empty() { - self.assemble_candidates_from_default_impls(obligation, &mut candidates)?; - } - debug!("candidate list size: {}", candidates.vec.len()); - Ok(candidates) - } - - fn assemble_candidates_from_projected_tys(&mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>) - { - debug!("assemble_candidates_for_projected_tys({:?})", obligation); - - // FIXME(#20297) -- just examining the self-type is very simplistic - - // before we go into the whole skolemization thing, just - // quickly check if the self-type is a projection at all. - let trait_def_id = match obligation.predicate.0.trait_ref.self_ty().sty { - ty::TyProjection(ref data) => data.trait_ref.def_id, - ty::TyInfer(ty::TyVar(_)) => { - self.tcx().sess.span_bug(obligation.cause.span, - "Self=_ should have been handled by assemble_candidates"); - } - _ => { return; } - }; - - debug!("assemble_candidates_for_projected_tys: trait_def_id={:?}", - trait_def_id); - - let result = self.infcx.probe(|snapshot| { - self.match_projection_obligation_against_bounds_from_trait(obligation, - snapshot) - }); - - if result { - candidates.vec.push(ProjectionCandidate); - } - } - - fn match_projection_obligation_against_bounds_from_trait( - &mut self, - obligation: &TraitObligation<'tcx>, - snapshot: &infer::CombinedSnapshot) - -> bool - { - let poly_trait_predicate = - self.infcx().resolve_type_vars_if_possible(&obligation.predicate); - let (skol_trait_predicate, skol_map) = - self.infcx().skolemize_late_bound_regions(&poly_trait_predicate, snapshot); - debug!("match_projection_obligation_against_bounds_from_trait: \ - skol_trait_predicate={:?} skol_map={:?}", - skol_trait_predicate, - skol_map); - - let projection_trait_ref = match skol_trait_predicate.trait_ref.self_ty().sty { - ty::TyProjection(ref data) => &data.trait_ref, - _ => { - self.tcx().sess.span_bug( - obligation.cause.span, - &format!("match_projection_obligation_against_bounds_from_trait() called \ - but self-ty not a projection: {:?}", - skol_trait_predicate.trait_ref.self_ty())); - } - }; - debug!("match_projection_obligation_against_bounds_from_trait: \ - projection_trait_ref={:?}", - projection_trait_ref); - - let trait_predicates = self.tcx().lookup_predicates(projection_trait_ref.def_id); - let bounds = trait_predicates.instantiate(self.tcx(), projection_trait_ref.substs); - debug!("match_projection_obligation_against_bounds_from_trait: \ - bounds={:?}", - bounds); - - let matching_bound = - util::elaborate_predicates(self.tcx(), bounds.predicates.into_vec()) - .filter_to_traits() - .find( - |bound| self.infcx.probe( - |_| self.match_projection(obligation, - bound.clone(), - skol_trait_predicate.trait_ref.clone(), - &skol_map, - snapshot))); - - debug!("match_projection_obligation_against_bounds_from_trait: \ - matching_bound={:?}", - matching_bound); - match matching_bound { - None => false, - Some(bound) => { - // Repeat the successful match, if any, this time outside of a probe. - let result = self.match_projection(obligation, - bound, - skol_trait_predicate.trait_ref.clone(), - &skol_map, - snapshot); - assert!(result); - true - } - } - } - - fn match_projection(&mut self, - obligation: &TraitObligation<'tcx>, - trait_bound: ty::PolyTraitRef<'tcx>, - skol_trait_ref: ty::TraitRef<'tcx>, - skol_map: &infer::SkolemizationMap, - snapshot: &infer::CombinedSnapshot) - -> bool - { - assert!(!skol_trait_ref.has_escaping_regions()); - let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); - match self.infcx.sub_poly_trait_refs(false, - origin, - trait_bound.clone(), - ty::Binder(skol_trait_ref.clone())) { - Ok(()) => { } - Err(_) => { return false; } - } - - self.infcx.leak_check(skol_map, snapshot).is_ok() - } - - /// Given an obligation like ``, search the obligations that the caller - /// supplied to find out whether it is listed among them. - /// - /// Never affects inference environment. - fn assemble_candidates_from_caller_bounds<'o>(&mut self, - stack: &TraitObligationStack<'o, 'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>) - -> Result<(),SelectionError<'tcx>> - { - debug!("assemble_candidates_from_caller_bounds({:?})", - stack.obligation); - - let all_bounds = - self.param_env().caller_bounds - .iter() - .filter_map(|o| o.to_opt_poly_trait_ref()); - - let matching_bounds = - all_bounds.filter( - |bound| self.evaluate_where_clause(stack, bound.clone()).may_apply()); - - let param_candidates = - matching_bounds.map(|bound| ParamCandidate(bound)); - - candidates.vec.extend(param_candidates); - - Ok(()) - } - - fn evaluate_where_clause<'o>(&mut self, - stack: &TraitObligationStack<'o, 'tcx>, - where_clause_trait_ref: ty::PolyTraitRef<'tcx>) - -> EvaluationResult - { - self.infcx().probe(move |_| { - match self.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { - Ok(obligations) => { - self.evaluate_predicates_recursively(stack.list(), obligations.iter()) - } - Err(()) => EvaluatedToErr - } - }) - } - - /// Check for the artificial impl that the compiler will create for an obligation like `X : - /// FnMut<..>` where `X` is a closure type. - /// - /// Note: the type parameters on a closure candidate are modeled as *output* type - /// parameters and hence do not affect whether this trait is a match or not. They will be - /// unified during the confirmation step. - fn assemble_closure_candidates(&mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>) - -> Result<(),SelectionError<'tcx>> - { - let kind = match self.tcx().lang_items.fn_trait_kind(obligation.predicate.0.def_id()) { - Some(k) => k, - None => { return Ok(()); } - }; - - // ok to skip binder because the substs on closure types never - // touch bound regions, they just capture the in-scope - // type/region parameters - let self_ty = *obligation.self_ty().skip_binder(); - let (closure_def_id, substs) = match self_ty.sty { - ty::TyClosure(id, ref substs) => (id, substs), - ty::TyInfer(ty::TyVar(_)) => { - debug!("assemble_unboxed_closure_candidates: ambiguous self-type"); - candidates.ambiguous = true; - return Ok(()); - } - _ => { return Ok(()); } - }; - - debug!("assemble_unboxed_candidates: self_ty={:?} kind={:?} obligation={:?}", - self_ty, - kind, - obligation); - - match self.infcx.closure_kind(closure_def_id) { - Some(closure_kind) => { - debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind); - if closure_kind.extends(kind) { - candidates.vec.push(ClosureCandidate(closure_def_id, substs)); - } - } - None => { - debug!("assemble_unboxed_candidates: closure_kind not yet known"); - candidates.ambiguous = true; - } - } - - Ok(()) - } - - /// Implement one of the `Fn()` family for a fn pointer. - fn assemble_fn_pointer_candidates(&mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>) - -> Result<(),SelectionError<'tcx>> - { - // We provide impl of all fn traits for fn pointers. - if self.tcx().lang_items.fn_trait_kind(obligation.predicate.def_id()).is_none() { - return Ok(()); - } - - // ok to skip binder because what we are inspecting doesn't involve bound regions - let self_ty = *obligation.self_ty().skip_binder(); - match self_ty.sty { - ty::TyInfer(ty::TyVar(_)) => { - debug!("assemble_fn_pointer_candidates: ambiguous self-type"); - candidates.ambiguous = true; // could wind up being a fn() type - } - - // provide an impl, but only for suitable `fn` pointers - ty::TyFnDef(_, _, &ty::BareFnTy { - unsafety: hir::Unsafety::Normal, - abi: Abi::Rust, - sig: ty::Binder(ty::FnSig { - inputs: _, - output: ty::FnConverging(_), - variadic: false - }) - }) | - ty::TyFnPtr(&ty::BareFnTy { - unsafety: hir::Unsafety::Normal, - abi: Abi::Rust, - sig: ty::Binder(ty::FnSig { - inputs: _, - output: ty::FnConverging(_), - variadic: false - }) - }) => { - candidates.vec.push(FnPointerCandidate); - } - - _ => { } - } - - Ok(()) - } - - /// Search for impls that might apply to `obligation`. - fn assemble_candidates_from_impls(&mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>) - -> Result<(), SelectionError<'tcx>> - { - debug!("assemble_candidates_from_impls(obligation={:?})", obligation); - - let def = self.tcx().lookup_trait_def(obligation.predicate.def_id()); - - def.for_each_relevant_impl( - self.tcx(), - obligation.predicate.0.trait_ref.self_ty(), - |impl_def_id| { - self.infcx.probe(|snapshot| { - if let Ok(_) = self.match_impl(impl_def_id, obligation, snapshot) { - candidates.vec.push(ImplCandidate(impl_def_id)); - } - }); - } - ); - - Ok(()) - } - - fn assemble_candidates_from_default_impls(&mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>) - -> Result<(), SelectionError<'tcx>> - { - // OK to skip binder here because the tests we do below do not involve bound regions - let self_ty = *obligation.self_ty().skip_binder(); - debug!("assemble_candidates_from_default_impls(self_ty={:?})", self_ty); - - let def_id = obligation.predicate.def_id(); - - if self.tcx().trait_has_default_impl(def_id) { - match self_ty.sty { - ty::TyTrait(..) => { - // For object types, we don't know what the closed - // over types are. For most traits, this means we - // conservatively say nothing; a candidate may be - // added by `assemble_candidates_from_object_ty`. - // However, for the kind of magic reflect trait, - // we consider it to be implemented even for - // object types, because it just lets you reflect - // onto the object type, not into the object's - // interior. - if self.tcx().has_attr(def_id, "rustc_reflect_like") { - candidates.vec.push(DefaultImplObjectCandidate(def_id)); - } - } - ty::TyParam(..) | - ty::TyProjection(..) => { - // In these cases, we don't know what the actual - // type is. Therefore, we cannot break it down - // into its constituent types. So we don't - // consider the `..` impl but instead just add no - // candidates: this means that typeck will only - // succeed if there is another reason to believe - // that this obligation holds. That could be a - // where-clause or, in the case of an object type, - // it could be that the object type lists the - // trait (e.g. `Foo+Send : Send`). See - // `compile-fail/typeck-default-trait-impl-send-param.rs` - // for an example of a test case that exercises - // this path. - } - ty::TyInfer(ty::TyVar(_)) => { - // the defaulted impl might apply, we don't know - candidates.ambiguous = true; - } - _ => { - candidates.vec.push(DefaultImplCandidate(def_id.clone())) - } - } - } - - Ok(()) - } - - /// Search for impls that might apply to `obligation`. - fn assemble_candidates_from_object_ty(&mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>) - { - debug!("assemble_candidates_from_object_ty(self_ty={:?})", - obligation.self_ty().skip_binder()); - - // Object-safety candidates are only applicable to object-safe - // traits. Including this check is useful because it helps - // inference in cases of traits like `BorrowFrom`, which are - // not object-safe, and which rely on being able to infer the - // self-type from one of the other inputs. Without this check, - // these cases wind up being considered ambiguous due to a - // (spurious) ambiguity introduced here. - let predicate_trait_ref = obligation.predicate.to_poly_trait_ref(); - if !object_safety::is_object_safe(self.tcx(), predicate_trait_ref.def_id()) { - return; - } - - self.infcx.commit_if_ok(|snapshot| { - let (self_ty, _) = - self.infcx().skolemize_late_bound_regions(&obligation.self_ty(), snapshot); - let poly_trait_ref = match self_ty.sty { - ty::TyTrait(ref data) => { - match self.tcx().lang_items.to_builtin_kind(obligation.predicate.def_id()) { - Some(bound @ ty::BoundSend) | Some(bound @ ty::BoundSync) => { - if data.bounds.builtin_bounds.contains(&bound) { - debug!("assemble_candidates_from_object_ty: matched builtin bound, \ - pushing candidate"); - candidates.vec.push(BuiltinObjectCandidate); - return Ok(()); - } - } - _ => {} - } - - data.principal_trait_ref_with_self_ty(self.tcx(), self_ty) - } - ty::TyInfer(ty::TyVar(_)) => { - debug!("assemble_candidates_from_object_ty: ambiguous"); - candidates.ambiguous = true; // could wind up being an object type - return Ok(()); - } - _ => { - return Ok(()); - } - }; - - debug!("assemble_candidates_from_object_ty: poly_trait_ref={:?}", - poly_trait_ref); - - // Count only those upcast versions that match the trait-ref - // we are looking for. Specifically, do not only check for the - // correct trait, but also the correct type parameters. - // For example, we may be trying to upcast `Foo` to `Bar`, - // but `Foo` is declared as `trait Foo : Bar`. - let upcast_trait_refs = - util::supertraits(self.tcx(), poly_trait_ref) - .filter(|upcast_trait_ref| { - self.infcx.probe(|_| { - let upcast_trait_ref = upcast_trait_ref.clone(); - self.match_poly_trait_ref(obligation, upcast_trait_ref).is_ok() - }) - }) - .count(); - - if upcast_trait_refs > 1 { - // can be upcast in many ways; need more type information - candidates.ambiguous = true; - } else if upcast_trait_refs == 1 { - candidates.vec.push(ObjectCandidate); - } - - Ok::<(),()>(()) - }).unwrap(); - } - - /// Search for unsizing that might apply to `obligation`. - fn assemble_candidates_for_unsizing(&mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>) { - // We currently never consider higher-ranked obligations e.g. - // `for<'a> &'a T: Unsize` to be implemented. This is not - // because they are a priori invalid, and we could potentially add support - // for them later, it's just that there isn't really a strong need for it. - // A `T: Unsize` obligation is always used as part of a `T: CoerceUnsize` - // impl, and those are generally applied to concrete types. - // - // That said, one might try to write a fn with a where clause like - // for<'a> Foo<'a, T>: Unsize> - // where the `'a` is kind of orthogonal to the relevant part of the `Unsize`. - // Still, you'd be more likely to write that where clause as - // T: Trait - // so it seems ok if we (conservatively) fail to accept that `Unsize` - // obligation above. Should be possible to extend this in the future. - let source = match self.tcx().no_late_bound_regions(&obligation.self_ty()) { - Some(t) => t, - None => { - // Don't add any candidates if there are bound regions. - return; - } - }; - let target = obligation.predicate.0.input_types()[0]; - - debug!("assemble_candidates_for_unsizing(source={:?}, target={:?})", - source, target); - - let may_apply = match (&source.sty, &target.sty) { - // Trait+Kx+'a -> Trait+Ky+'b (upcasts). - (&ty::TyTrait(ref data_a), &ty::TyTrait(ref data_b)) => { - // Upcasts permit two things: - // - // 1. Dropping builtin bounds, e.g. `Foo+Send` to `Foo` - // 2. Tightening the region bound, e.g. `Foo+'a` to `Foo+'b` if `'a : 'b` - // - // Note that neither of these changes requires any - // change at runtime. Eventually this will be - // generalized. - // - // We always upcast when we can because of reason - // #2 (region bounds). - data_a.principal.def_id() == data_a.principal.def_id() && - data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds) - } - - // T -> Trait. - (_, &ty::TyTrait(_)) => true, - - // Ambiguous handling is below T -> Trait, because inference - // variables can still implement Unsize and nested - // obligations will have the final say (likely deferred). - (&ty::TyInfer(ty::TyVar(_)), _) | - (_, &ty::TyInfer(ty::TyVar(_))) => { - debug!("assemble_candidates_for_unsizing: ambiguous"); - candidates.ambiguous = true; - false - } - - // [T; n] -> [T]. - (&ty::TyArray(_, _), &ty::TySlice(_)) => true, - - // Struct -> Struct. - (&ty::TyStruct(def_id_a, _), &ty::TyStruct(def_id_b, _)) => { - def_id_a == def_id_b - } - - _ => false - }; - - if may_apply { - candidates.vec.push(BuiltinUnsizeCandidate); - } - } - - /////////////////////////////////////////////////////////////////////////// - // WINNOW - // - // Winnowing is the process of attempting to resolve ambiguity by - // probing further. During the winnowing process, we unify all - // type variables (ignoring skolemization) and then we also - // attempt to evaluate recursive bounds to see if they are - // satisfied. - - /// Returns true if `candidate_i` should be dropped in favor of - /// `candidate_j`. Generally speaking we will drop duplicate - /// candidates and prefer where-clause candidates. - /// Returns true if `victim` should be dropped in favor of - /// `other`. Generally speaking we will drop duplicate - /// candidates and prefer where-clause candidates. - /// - /// See the comment for "SelectionCandidate" for more details. - fn candidate_should_be_dropped_in_favor_of<'o>( - &mut self, - victim: &EvaluatedCandidate<'tcx>, - other: &EvaluatedCandidate<'tcx>) - -> bool - { - if victim.candidate == other.candidate { - return true; - } - - match other.candidate { - ObjectCandidate | - ParamCandidate(_) | ProjectionCandidate => match victim.candidate { - DefaultImplCandidate(..) => { - self.tcx().sess.bug( - "default implementations shouldn't be recorded \ - when there are other valid candidates"); - } - ImplCandidate(..) | - ClosureCandidate(..) | - FnPointerCandidate | - BuiltinObjectCandidate | - BuiltinUnsizeCandidate | - DefaultImplObjectCandidate(..) | - BuiltinCandidate(..) => { - // We have a where-clause so don't go around looking - // for impls. - true - } - ObjectCandidate | - ProjectionCandidate => { - // Arbitrarily give param candidates priority - // over projection and object candidates. - true - }, - ParamCandidate(..) => false, - }, - ImplCandidate(other_def) => { - // See if we can toss out `victim` based on specialization. - // This requires us to know *for sure* that the `other` impl applies - // i.e. EvaluatedToOk: - if other.evaluation == EvaluatedToOk { - if let ImplCandidate(victim_def) = victim.candidate { - return traits::specializes(self.tcx(), other_def, victim_def); - } - } - - false - }, - _ => false - } - } - - /////////////////////////////////////////////////////////////////////////// - // BUILTIN BOUNDS - // - // These cover the traits that are built-in to the language - // itself. This includes `Copy` and `Sized` for sure. For the - // moment, it also includes `Send` / `Sync` and a few others, but - // those will hopefully change to library-defined traits in the - // future. - - fn assemble_builtin_bound_candidates<'o>(&mut self, - bound: ty::BuiltinBound, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>) - -> Result<(),SelectionError<'tcx>> - { - match self.builtin_bound(bound, obligation) { - Ok(If(..)) => { - debug!("builtin_bound: bound={:?}", - bound); - candidates.vec.push(BuiltinCandidate(bound)); - Ok(()) - } - Ok(ParameterBuiltin) => { Ok(()) } - Ok(AmbiguousBuiltin) => { - debug!("assemble_builtin_bound_candidates: ambiguous builtin"); - Ok(candidates.ambiguous = true) - } - Err(e) => { Err(e) } - } - } - - fn builtin_bound(&mut self, - bound: ty::BuiltinBound, - obligation: &TraitObligation<'tcx>) - -> Result,SelectionError<'tcx>> - { - // Note: these tests operate on types that may contain bound - // regions. To be proper, we ought to skolemize here, but we - // forego the skolemization and defer it until the - // confirmation step. - - let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.self_ty()); - return match self_ty.sty { - ty::TyInfer(ty::IntVar(_)) | - ty::TyInfer(ty::FloatVar(_)) | - ty::TyUint(_) | - ty::TyInt(_) | - ty::TyBool | - ty::TyFloat(_) | - ty::TyFnDef(..) | - ty::TyFnPtr(_) | - ty::TyChar => { - // safe for everything - ok_if(Vec::new()) - } - - ty::TyBox(_) => { // Box - match bound { - ty::BoundCopy => Err(Unimplemented), - - ty::BoundSized => ok_if(Vec::new()), - - ty::BoundSync | ty::BoundSend => { - self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()"); - } - } - } - - ty::TyRawPtr(..) => { // *const T, *mut T - match bound { - ty::BoundCopy | ty::BoundSized => ok_if(Vec::new()), - - ty::BoundSync | ty::BoundSend => { - self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()"); - } - } - } - - ty::TyTrait(ref data) => { - match bound { - ty::BoundSized => Err(Unimplemented), - ty::BoundCopy => { - if data.bounds.builtin_bounds.contains(&bound) { - ok_if(Vec::new()) - } else { - // Recursively check all supertraits to find out if any further - // bounds are required and thus we must fulfill. - let principal = - data.principal_trait_ref_with_self_ty(self.tcx(), - self.tcx().types.err); - let copy_def_id = obligation.predicate.def_id(); - for tr in util::supertraits(self.tcx(), principal) { - if tr.def_id() == copy_def_id { - return ok_if(Vec::new()) - } - } - - Err(Unimplemented) - } - } - ty::BoundSync | ty::BoundSend => { - self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()"); - } - } - } - - ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl }) => { - // &mut T or &T - match bound { - ty::BoundCopy => { - match mutbl { - // &mut T is affine and hence never `Copy` - hir::MutMutable => Err(Unimplemented), - - // &T is always copyable - hir::MutImmutable => ok_if(Vec::new()), - } - } - - ty::BoundSized => ok_if(Vec::new()), - - ty::BoundSync | ty::BoundSend => { - self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()"); - } - } - } - - ty::TyArray(element_ty, _) => { - // [T; n] - match bound { - ty::BoundCopy => ok_if(vec![element_ty]), - ty::BoundSized => ok_if(Vec::new()), - ty::BoundSync | ty::BoundSend => { - self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()"); - } - } - } - - ty::TyStr | ty::TySlice(_) => { - match bound { - ty::BoundSync | ty::BoundSend => { - self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()"); - } - - ty::BoundCopy | ty::BoundSized => Err(Unimplemented), - } - } - - // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet - ty::TyTuple(ref tys) => ok_if(tys.clone()), - - ty::TyClosure(_, ref substs) => { - // FIXME -- This case is tricky. In the case of by-ref - // closures particularly, we need the results of - // inference to decide how to reflect the type of each - // upvar (the upvar may have type `T`, but the runtime - // type could be `&mut`, `&`, or just `T`). For now, - // though, we'll do this unsoundly and assume that all - // captures are by value. Really what we ought to do - // is reserve judgement and then intertwine this - // analysis with closure inference. - - // Unboxed closures shouldn't be - // implicitly copyable - if bound == ty::BoundCopy { - return Ok(ParameterBuiltin); - } - - // Upvars are always local variables or references to - // local variables, and local variables cannot be - // unsized, so the closure struct as a whole must be - // Sized. - if bound == ty::BoundSized { - return ok_if(Vec::new()); - } - - ok_if(substs.upvar_tys.clone()) - } - - ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { - let types: Vec = def.all_fields().map(|f| { - f.ty(self.tcx(), substs) - }).collect(); - nominal(bound, types) - } - - ty::TyProjection(_) | ty::TyParam(_) => { - // Note: A type parameter is only considered to meet a - // particular bound if there is a where clause telling - // us that it does, and that case is handled by - // `assemble_candidates_from_caller_bounds()`. - Ok(ParameterBuiltin) - } - - ty::TyInfer(ty::TyVar(_)) => { - // Unbound type variable. Might or might not have - // applicable impls and so forth, depending on what - // those type variables wind up being bound to. - debug!("assemble_builtin_bound_candidates: ambiguous builtin"); - Ok(AmbiguousBuiltin) - } - - ty::TyError => ok_if(Vec::new()), - - ty::TyInfer(ty::FreshTy(_)) - | ty::TyInfer(ty::FreshIntTy(_)) - | ty::TyInfer(ty::FreshFloatTy(_)) => { - self.tcx().sess.bug( - &format!( - "asked to assemble builtin bounds of unexpected type: {:?}", - self_ty)); - } - }; - - fn ok_if<'tcx>(v: Vec>) - -> Result, SelectionError<'tcx>> { - Ok(If(ty::Binder(v))) - } - - fn nominal<'cx, 'tcx>(bound: ty::BuiltinBound, - types: Vec>) - -> Result, SelectionError<'tcx>> - { - // First check for markers and other nonsense. - match bound { - // Fallback to whatever user-defined impls exist in this case. - ty::BoundCopy => Ok(ParameterBuiltin), - - // Sized if all the component types are sized. - ty::BoundSized => ok_if(types), - - // Shouldn't be coming through here. - ty::BoundSend | ty::BoundSync => unreachable!(), - } - } - } - - /// For default impls, we need to break apart a type into its - /// "constituent types" -- meaning, the types that it contains. - /// - /// Here are some (simple) examples: - /// - /// ``` - /// (i32, u32) -> [i32, u32] - /// Foo where struct Foo { x: i32, y: u32 } -> [i32, u32] - /// Bar where struct Bar { x: T, y: u32 } -> [i32, u32] - /// Zed where enum Zed { A(T), B(u32) } -> [i32, u32] - /// ``` - fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec> { - match t.sty { - ty::TyUint(_) | - ty::TyInt(_) | - ty::TyBool | - ty::TyFloat(_) | - ty::TyFnDef(..) | - ty::TyFnPtr(_) | - ty::TyStr | - ty::TyError | - ty::TyInfer(ty::IntVar(_)) | - ty::TyInfer(ty::FloatVar(_)) | - ty::TyChar => { - Vec::new() - } - - ty::TyTrait(..) | - ty::TyParam(..) | - ty::TyProjection(..) | - ty::TyInfer(ty::TyVar(_)) | - ty::TyInfer(ty::FreshTy(_)) | - ty::TyInfer(ty::FreshIntTy(_)) | - ty::TyInfer(ty::FreshFloatTy(_)) => { - self.tcx().sess.bug( - &format!( - "asked to assemble constituent types of unexpected type: {:?}", - t)); - } - - ty::TyBox(referent_ty) => { // Box - vec![referent_ty] - } - - ty::TyRawPtr(ty::TypeAndMut { ty: element_ty, ..}) | - ty::TyRef(_, ty::TypeAndMut { ty: element_ty, ..}) => { - vec![element_ty] - }, - - ty::TyArray(element_ty, _) | ty::TySlice(element_ty) => { - vec![element_ty] - } - - ty::TyTuple(ref tys) => { - // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet - tys.clone() - } - - ty::TyClosure(_, ref substs) => { - // FIXME(#27086). We are invariant w/r/t our - // substs.func_substs, but we don't see them as - // constituent types; this seems RIGHT but also like - // something that a normal type couldn't simulate. Is - // this just a gap with the way that PhantomData and - // OIBIT interact? That is, there is no way to say - // "make me invariant with respect to this TYPE, but - // do not act as though I can reach it" - substs.upvar_tys.clone() - } - - // for `PhantomData`, we pass `T` - ty::TyStruct(def, substs) if def.is_phantom_data() => { - substs.types.get_slice(TypeSpace).to_vec() - } - - ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { - def.all_fields() - .map(|f| f.ty(self.tcx(), substs)) - .collect() - } - } - } - - fn collect_predicates_for_types(&mut self, - obligation: &TraitObligation<'tcx>, - trait_def_id: DefId, - types: ty::Binder>>) - -> Vec> - { - let derived_cause = match self.tcx().lang_items.to_builtin_kind(trait_def_id) { - Some(_) => { - self.derived_cause(obligation, BuiltinDerivedObligation) - }, - None => { - self.derived_cause(obligation, ImplDerivedObligation) - } - }; - - // Because the types were potentially derived from - // higher-ranked obligations they may reference late-bound - // regions. For example, `for<'a> Foo<&'a int> : Copy` would - // yield a type like `for<'a> &'a int`. In general, we - // maintain the invariant that we never manipulate bound - // regions, so we have to process these bound regions somehow. - // - // The strategy is to: - // - // 1. Instantiate those regions to skolemized regions (e.g., - // `for<'a> &'a int` becomes `&0 int`. - // 2. Produce something like `&'0 int : Copy` - // 3. Re-bind the regions back to `for<'a> &'a int : Copy` - - // Move the binder into the individual types - let bound_types: Vec>> = - types.skip_binder() - .iter() - .map(|&nested_ty| ty::Binder(nested_ty)) - .collect(); - - // For each type, produce a vector of resulting obligations - let obligations: Result>, _> = bound_types.iter().map(|nested_ty| { - self.infcx.commit_if_ok(|snapshot| { - let (skol_ty, skol_map) = - self.infcx().skolemize_late_bound_regions(nested_ty, snapshot); - let Normalized { value: normalized_ty, mut obligations } = - project::normalize_with_depth(self, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &skol_ty); - let skol_obligation = - util::predicate_for_trait_def(self.tcx(), - derived_cause.clone(), - trait_def_id, - obligation.recursion_depth + 1, - normalized_ty, - vec![]); - obligations.push(skol_obligation); - Ok(self.infcx().plug_leaks(skol_map, snapshot, &obligations)) - }) - }).collect(); - - // Flatten those vectors (couldn't do it above due `collect`) - match obligations { - Ok(obligations) => obligations.into_iter().flat_map(|o| o).collect(), - Err(ErrorReported) => Vec::new(), - } - } - - /////////////////////////////////////////////////////////////////////////// - // CONFIRMATION - // - // Confirmation unifies the output type parameters of the trait - // with the values found in the obligation, possibly yielding a - // type error. See `README.md` for more details. - - fn confirm_candidate(&mut self, - obligation: &TraitObligation<'tcx>, - candidate: SelectionCandidate<'tcx>) - -> Result,SelectionError<'tcx>> - { - debug!("confirm_candidate({:?}, {:?})", - obligation, - candidate); - - match candidate { - BuiltinCandidate(builtin_bound) => { - Ok(VtableBuiltin( - self.confirm_builtin_candidate(obligation, builtin_bound)?)) - } - - ParamCandidate(param) => { - let obligations = self.confirm_param_candidate(obligation, param); - Ok(VtableParam(obligations)) - } - - DefaultImplCandidate(trait_def_id) => { - let data = self.confirm_default_impl_candidate(obligation, trait_def_id); - Ok(VtableDefaultImpl(data)) - } - - DefaultImplObjectCandidate(trait_def_id) => { - let data = self.confirm_default_impl_object_candidate(obligation, trait_def_id); - Ok(VtableDefaultImpl(data)) - } - - ImplCandidate(impl_def_id) => { - let vtable_impl = - self.confirm_impl_candidate(obligation, impl_def_id)?; - Ok(VtableImpl(vtable_impl)) - } - - ClosureCandidate(closure_def_id, substs) => { - let vtable_closure = - self.confirm_closure_candidate(obligation, closure_def_id, substs)?; - Ok(VtableClosure(vtable_closure)) - } - - BuiltinObjectCandidate => { - // This indicates something like `(Trait+Send) : - // Send`. In this case, we know that this holds - // because that's what the object type is telling us, - // and there's really no additional obligations to - // prove and no types in particular to unify etc. - Ok(VtableParam(Vec::new())) - } - - ObjectCandidate => { - let data = self.confirm_object_candidate(obligation); - Ok(VtableObject(data)) - } - - FnPointerCandidate => { - let fn_type = - self.confirm_fn_pointer_candidate(obligation)?; - Ok(VtableFnPointer(fn_type)) - } - - ProjectionCandidate => { - self.confirm_projection_candidate(obligation); - Ok(VtableParam(Vec::new())) - } - - BuiltinUnsizeCandidate => { - let data = self.confirm_builtin_unsize_candidate(obligation)?; - Ok(VtableBuiltin(data)) - } - } - } - - fn confirm_projection_candidate(&mut self, - obligation: &TraitObligation<'tcx>) - { - let _: Result<(),()> = - self.infcx.commit_if_ok(|snapshot| { - let result = - self.match_projection_obligation_against_bounds_from_trait(obligation, - snapshot); - assert!(result); - Ok(()) - }); - } - - fn confirm_param_candidate(&mut self, - obligation: &TraitObligation<'tcx>, - param: ty::PolyTraitRef<'tcx>) - -> Vec> - { - debug!("confirm_param_candidate({:?},{:?})", - obligation, - param); - - // During evaluation, we already checked that this - // where-clause trait-ref could be unified with the obligation - // trait-ref. Repeat that unification now without any - // transactional boundary; it should not fail. - match self.match_where_clause_trait_ref(obligation, param.clone()) { - Ok(obligations) => obligations, - Err(()) => { - self.tcx().sess.bug( - &format!("Where clause `{:?}` was applicable to `{:?}` but now is not", - param, - obligation)); - } - } - } - - fn confirm_builtin_candidate(&mut self, - obligation: &TraitObligation<'tcx>, - bound: ty::BuiltinBound) - -> Result>, - SelectionError<'tcx>> - { - debug!("confirm_builtin_candidate({:?})", - obligation); - - match self.builtin_bound(bound, obligation)? { - If(nested) => Ok(self.vtable_builtin_data(obligation, bound, nested)), - AmbiguousBuiltin | ParameterBuiltin => { - self.tcx().sess.span_bug( - obligation.cause.span, - &format!("builtin bound for {:?} was ambig", - obligation)); - } - } - } - - fn vtable_builtin_data(&mut self, - obligation: &TraitObligation<'tcx>, - bound: ty::BuiltinBound, - nested: ty::Binder>>) - -> VtableBuiltinData> - { - debug!("vtable_builtin_data(obligation={:?}, bound={:?}, nested={:?})", - obligation, bound, nested); - - let trait_def = match self.tcx().lang_items.from_builtin_kind(bound) { - Ok(def_id) => def_id, - Err(_) => { - self.tcx().sess.bug("builtin trait definition not found"); - } - }; - - let obligations = self.collect_predicates_for_types(obligation, trait_def, nested); - - debug!("vtable_builtin_data: obligations={:?}", - obligations); - - VtableBuiltinData { nested: obligations } - } - - /// This handles the case where a `impl Foo for ..` impl is being used. - /// The idea is that the impl applies to `X : Foo` if the following conditions are met: - /// - /// 1. For each constituent type `Y` in `X`, `Y : Foo` holds - /// 2. For each where-clause `C` declared on `Foo`, `[Self => X] C` holds. - fn confirm_default_impl_candidate(&mut self, - obligation: &TraitObligation<'tcx>, - trait_def_id: DefId) - -> VtableDefaultImplData> - { - debug!("confirm_default_impl_candidate({:?}, {:?})", - obligation, - trait_def_id); - - // binder is moved below - let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty()); - let types = self.constituent_types_for_ty(self_ty); - self.vtable_default_impl(obligation, trait_def_id, ty::Binder(types)) - } - - fn confirm_default_impl_object_candidate(&mut self, - obligation: &TraitObligation<'tcx>, - trait_def_id: DefId) - -> VtableDefaultImplData> - { - debug!("confirm_default_impl_object_candidate({:?}, {:?})", - obligation, - trait_def_id); - - assert!(self.tcx().has_attr(trait_def_id, "rustc_reflect_like")); - - // OK to skip binder, it is reintroduced below - let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty()); - match self_ty.sty { - ty::TyTrait(ref data) => { - // OK to skip the binder, it is reintroduced below - let input_types = data.principal.skip_binder().substs.types.get_slice(TypeSpace); - let assoc_types = data.bounds.projection_bounds - .iter() - .map(|pb| pb.skip_binder().ty); - let all_types: Vec<_> = input_types.iter().cloned() - .chain(assoc_types) - .collect(); - - // reintroduce the two binding levels we skipped, then flatten into one - let all_types = ty::Binder(ty::Binder(all_types)); - let all_types = self.tcx().flatten_late_bound_regions(&all_types); - - self.vtable_default_impl(obligation, trait_def_id, all_types) - } - _ => { - self.tcx().sess.bug( - &format!( - "asked to confirm default object implementation for non-object type: {:?}", - self_ty)); - } - } - } - - /// See `confirm_default_impl_candidate` - fn vtable_default_impl(&mut self, - obligation: &TraitObligation<'tcx>, - trait_def_id: DefId, - nested: ty::Binder>>) - -> VtableDefaultImplData> - { - debug!("vtable_default_impl_data: nested={:?}", nested); - - let mut obligations = self.collect_predicates_for_types(obligation, - trait_def_id, - nested); - - let trait_obligations: Result,()> = self.infcx.commit_if_ok(|snapshot| { - let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); - let (trait_ref, skol_map) = - self.infcx().skolemize_late_bound_regions(&poly_trait_ref, snapshot); - Ok(self.impl_or_trait_obligations(obligation.cause.clone(), - obligation.recursion_depth + 1, - trait_def_id, - &trait_ref.substs, - skol_map, - snapshot)) - }); - - // no Errors in that code above - obligations.append(&mut trait_obligations.unwrap()); - - debug!("vtable_default_impl_data: obligations={:?}", obligations); - - VtableDefaultImplData { - trait_def_id: trait_def_id, - nested: obligations - } - } - - fn confirm_impl_candidate(&mut self, - obligation: &TraitObligation<'tcx>, - impl_def_id: DefId) - -> Result>, - SelectionError<'tcx>> - { - debug!("confirm_impl_candidate({:?},{:?})", - obligation, - impl_def_id); - - // First, create the substitutions by matching the impl again, - // this time not in a probe. - self.infcx.commit_if_ok(|snapshot| { - let (substs, skol_map) = - self.rematch_impl(impl_def_id, obligation, - snapshot); - debug!("confirm_impl_candidate substs={:?}", substs); - Ok(self.vtable_impl(impl_def_id, substs, obligation.cause.clone(), - obligation.recursion_depth + 1, skol_map, snapshot)) - }) - } - - fn vtable_impl(&mut self, - impl_def_id: DefId, - mut substs: Normalized<'tcx, Substs<'tcx>>, - cause: ObligationCause<'tcx>, - recursion_depth: usize, - skol_map: infer::SkolemizationMap, - snapshot: &infer::CombinedSnapshot) - -> VtableImplData<'tcx, PredicateObligation<'tcx>> - { - debug!("vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={}, skol_map={:?})", - impl_def_id, - substs, - recursion_depth, - skol_map); - - let mut impl_obligations = - self.impl_or_trait_obligations(cause, - recursion_depth, - impl_def_id, - &substs.value, - skol_map, - snapshot); - - debug!("vtable_impl: impl_def_id={:?} impl_obligations={:?}", - impl_def_id, - impl_obligations); - - // Because of RFC447, the impl-trait-ref and obligations - // are sufficient to determine the impl substs, without - // relying on projections in the impl-trait-ref. - // - // e.g. `impl> Foo<::T> for V` - impl_obligations.append(&mut substs.obligations); - - VtableImplData { impl_def_id: impl_def_id, - substs: self.tcx().mk_substs(substs.value), - nested: impl_obligations } - } - - fn confirm_object_candidate(&mut self, - obligation: &TraitObligation<'tcx>) - -> VtableObjectData<'tcx> - { - debug!("confirm_object_candidate({:?})", - obligation); - - // FIXME skipping binder here seems wrong -- we should - // probably flatten the binder from the obligation and the - // binder from the object. Have to try to make a broken test - // case that results. -nmatsakis - let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); - let poly_trait_ref = match self_ty.sty { - ty::TyTrait(ref data) => { - data.principal_trait_ref_with_self_ty(self.tcx(), self_ty) - } - _ => { - self.tcx().sess.span_bug(obligation.cause.span, - "object candidate with non-object"); - } - }; - - let mut upcast_trait_ref = None; - let vtable_base; - - { - // We want to find the first supertrait in the list of - // supertraits that we can unify with, and do that - // unification. We know that there is exactly one in the list - // where we can unify because otherwise select would have - // reported an ambiguity. (When we do find a match, also - // record it for later.) - let nonmatching = - util::supertraits(self.tcx(), poly_trait_ref) - .take_while(|&t| { - match - self.infcx.commit_if_ok( - |_| self.match_poly_trait_ref(obligation, t)) - { - Ok(_) => { upcast_trait_ref = Some(t); false } - Err(_) => { true } - } - }); - - // Additionally, for each of the nonmatching predicates that - // we pass over, we sum up the set of number of vtable - // entries, so that we can compute the offset for the selected - // trait. - vtable_base = - nonmatching.map(|t| util::count_own_vtable_entries(self.tcx(), t)) - .sum(); - - } - - VtableObjectData { - upcast_trait_ref: upcast_trait_ref.unwrap(), - vtable_base: vtable_base, - } - } - - fn confirm_fn_pointer_candidate(&mut self, - obligation: &TraitObligation<'tcx>) - -> Result,SelectionError<'tcx>> - { - debug!("confirm_fn_pointer_candidate({:?})", - obligation); - - // ok to skip binder; it is reintroduced below - let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); - let sig = self_ty.fn_sig(); - let trait_ref = - util::closure_trait_ref_and_return_type(self.tcx(), - obligation.predicate.def_id(), - self_ty, - sig, - util::TupleArgumentsFlag::Yes) - .map_bound(|(trait_ref, _)| trait_ref); - - self.confirm_poly_trait_refs(obligation.cause.clone(), - obligation.predicate.to_poly_trait_ref(), - trait_ref)?; - Ok(self_ty) - } - - fn confirm_closure_candidate(&mut self, - obligation: &TraitObligation<'tcx>, - closure_def_id: DefId, - substs: &ty::ClosureSubsts<'tcx>) - -> Result>, - SelectionError<'tcx>> - { - debug!("confirm_closure_candidate({:?},{:?},{:?})", - obligation, - closure_def_id, - substs); - - let Normalized { - value: trait_ref, - obligations - } = self.closure_trait_ref(obligation, closure_def_id, substs); - - debug!("confirm_closure_candidate(closure_def_id={:?}, trait_ref={:?}, obligations={:?})", - closure_def_id, - trait_ref, - obligations); - - self.confirm_poly_trait_refs(obligation.cause.clone(), - obligation.predicate.to_poly_trait_ref(), - trait_ref)?; - - Ok(VtableClosureData { - closure_def_id: closure_def_id, - substs: substs.clone(), - nested: obligations - }) - } - - /// In the case of closure types and fn pointers, - /// we currently treat the input type parameters on the trait as - /// outputs. This means that when we have a match we have only - /// considered the self type, so we have to go back and make sure - /// to relate the argument types too. This is kind of wrong, but - /// since we control the full set of impls, also not that wrong, - /// and it DOES yield better error messages (since we don't report - /// errors as if there is no applicable impl, but rather report - /// errors are about mismatched argument types. - /// - /// Here is an example. Imagine we have a closure expression - /// and we desugared it so that the type of the expression is - /// `Closure`, and `Closure` expects an int as argument. Then it - /// is "as if" the compiler generated this impl: - /// - /// impl Fn(int) for Closure { ... } - /// - /// Now imagine our obligation is `Fn(usize) for Closure`. So far - /// we have matched the self-type `Closure`. At this point we'll - /// compare the `int` to `usize` and generate an error. - /// - /// Note that this checking occurs *after* the impl has selected, - /// because these output type parameters should not affect the - /// selection of the impl. Therefore, if there is a mismatch, we - /// report an error to the user. - fn confirm_poly_trait_refs(&mut self, - obligation_cause: ObligationCause, - obligation_trait_ref: ty::PolyTraitRef<'tcx>, - expected_trait_ref: ty::PolyTraitRef<'tcx>) - -> Result<(), SelectionError<'tcx>> - { - let origin = TypeOrigin::RelateOutputImplTypes(obligation_cause.span); - - let obligation_trait_ref = obligation_trait_ref.clone(); - match self.infcx.sub_poly_trait_refs(false, - origin, - expected_trait_ref.clone(), - obligation_trait_ref.clone()) { - Ok(()) => Ok(()), - Err(e) => Err(OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e)) - } - } - - fn confirm_builtin_unsize_candidate(&mut self, - obligation: &TraitObligation<'tcx>,) - -> Result>, - SelectionError<'tcx>> { - let tcx = self.tcx(); - - // assemble_candidates_for_unsizing should ensure there are no late bound - // regions here. See the comment there for more details. - let source = self.infcx.shallow_resolve( - tcx.no_late_bound_regions(&obligation.self_ty()).unwrap()); - let target = self.infcx.shallow_resolve(obligation.predicate.0.input_types()[0]); - - debug!("confirm_builtin_unsize_candidate(source={:?}, target={:?})", - source, target); - - let mut nested = vec![]; - match (&source.sty, &target.sty) { - // Trait+Kx+'a -> Trait+Ky+'b (upcasts). - (&ty::TyTrait(ref data_a), &ty::TyTrait(ref data_b)) => { - // See assemble_candidates_for_unsizing for more info. - let bounds = ty::ExistentialBounds { - region_bound: data_b.bounds.region_bound, - builtin_bounds: data_b.bounds.builtin_bounds, - projection_bounds: data_a.bounds.projection_bounds.clone(), - }; - - let new_trait = tcx.mk_trait(data_a.principal.clone(), bounds); - let origin = TypeOrigin::Misc(obligation.cause.span); - if self.infcx.sub_types(false, origin, new_trait, target).is_err() { - return Err(Unimplemented); - } - - // Register one obligation for 'a: 'b. - let cause = ObligationCause::new(obligation.cause.span, - obligation.cause.body_id, - ObjectCastObligation(target)); - let outlives = ty::OutlivesPredicate(data_a.bounds.region_bound, - data_b.bounds.region_bound); - nested.push(Obligation::with_depth(cause, - obligation.recursion_depth + 1, - ty::Binder(outlives).to_predicate())); - } - - // T -> Trait. - (_, &ty::TyTrait(ref data)) => { - let object_did = data.principal_def_id(); - if !object_safety::is_object_safe(tcx, object_did) { - return Err(TraitNotObjectSafe(object_did)); - } - - let cause = ObligationCause::new(obligation.cause.span, - obligation.cause.body_id, - ObjectCastObligation(target)); - let mut push = |predicate| { - nested.push(Obligation::with_depth(cause.clone(), - obligation.recursion_depth + 1, - predicate)); - }; - - // Create the obligation for casting from T to Trait. - push(data.principal_trait_ref_with_self_ty(tcx, source).to_predicate()); - - // We can only make objects from sized types. - let mut builtin_bounds = data.bounds.builtin_bounds; - builtin_bounds.insert(ty::BoundSized); - - // Create additional obligations for all the various builtin - // bounds attached to the object cast. (In other words, if the - // object type is Foo+Send, this would create an obligation - // for the Send check.) - for bound in &builtin_bounds { - if let Ok(tr) = util::trait_ref_for_builtin_bound(tcx, bound, source) { - push(tr.to_predicate()); - } else { - return Err(Unimplemented); - } - } - - // Create obligations for the projection predicates. - for bound in data.projection_bounds_with_self_ty(tcx, source) { - push(bound.to_predicate()); - } - - // If the type is `Foo+'a`, ensures that the type - // being cast to `Foo+'a` outlives `'a`: - let outlives = ty::OutlivesPredicate(source, - data.bounds.region_bound); - push(ty::Binder(outlives).to_predicate()); - } - - // [T; n] -> [T]. - (&ty::TyArray(a, _), &ty::TySlice(b)) => { - let origin = TypeOrigin::Misc(obligation.cause.span); - if self.infcx.sub_types(false, origin, a, b).is_err() { - return Err(Unimplemented); - } - } - - // Struct -> Struct. - (&ty::TyStruct(def, substs_a), &ty::TyStruct(_, substs_b)) => { - let fields = def - .all_fields() - .map(|f| f.unsubst_ty()) - .collect::>(); - - // The last field of the structure has to exist and contain type parameters. - let field = if let Some(&field) = fields.last() { - field - } else { - return Err(Unimplemented); - }; - let mut ty_params = vec![]; - for ty in field.walk() { - if let ty::TyParam(p) = ty.sty { - assert!(p.space == TypeSpace); - let idx = p.idx as usize; - if !ty_params.contains(&idx) { - ty_params.push(idx); - } - } - } - if ty_params.is_empty() { - return Err(Unimplemented); - } - - // Replace type parameters used in unsizing with - // TyError and ensure they do not affect any other fields. - // This could be checked after type collection for any struct - // with a potentially unsized trailing field. - let mut new_substs = substs_a.clone(); - for &i in &ty_params { - new_substs.types.get_mut_slice(TypeSpace)[i] = tcx.types.err; - } - for &ty in fields.split_last().unwrap().1 { - if ty.subst(tcx, &new_substs).references_error() { - return Err(Unimplemented); - } - } - - // Extract Field and Field from Struct and Struct. - let inner_source = field.subst(tcx, substs_a); - let inner_target = field.subst(tcx, substs_b); - - // Check that the source structure with the target's - // type parameters is a subtype of the target. - for &i in &ty_params { - let param_b = *substs_b.types.get(TypeSpace, i); - new_substs.types.get_mut_slice(TypeSpace)[i] = param_b; - } - let new_struct = tcx.mk_struct(def, tcx.mk_substs(new_substs)); - let origin = TypeOrigin::Misc(obligation.cause.span); - if self.infcx.sub_types(false, origin, new_struct, target).is_err() { - return Err(Unimplemented); - } - - // Construct the nested Field: Unsize> predicate. - nested.push(util::predicate_for_trait_def(tcx, - obligation.cause.clone(), - obligation.predicate.def_id(), - obligation.recursion_depth + 1, - inner_source, - vec![inner_target])); - } - - _ => unreachable!() - }; - - Ok(VtableBuiltinData { nested: nested }) - } - - /////////////////////////////////////////////////////////////////////////// - // Matching - // - // Matching is a common path used for both evaluation and - // confirmation. It basically unifies types that appear in impls - // and traits. This does affect the surrounding environment; - // therefore, when used during evaluation, match routines must be - // run inside of a `probe()` so that their side-effects are - // contained. - - fn rematch_impl(&mut self, - impl_def_id: DefId, - obligation: &TraitObligation<'tcx>, - snapshot: &infer::CombinedSnapshot) - -> (Normalized<'tcx, Substs<'tcx>>, infer::SkolemizationMap) - { - match self.match_impl(impl_def_id, obligation, snapshot) { - Ok((substs, skol_map)) => (substs, skol_map), - Err(()) => { - self.tcx().sess.bug( - &format!("Impl {:?} was matchable against {:?} but now is not", - impl_def_id, - obligation)); - } - } - } - - fn match_impl(&mut self, - impl_def_id: DefId, - obligation: &TraitObligation<'tcx>, - snapshot: &infer::CombinedSnapshot) - -> Result<(Normalized<'tcx, Substs<'tcx>>, - infer::SkolemizationMap), ()> - { - let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); - - // Before we create the substitutions and everything, first - // consider a "quick reject". This avoids creating more types - // and so forth that we need to. - if self.fast_reject_trait_refs(obligation, &impl_trait_ref) { - return Err(()); - } - - let (skol_obligation, skol_map) = self.infcx().skolemize_late_bound_regions( - &obligation.predicate, - snapshot); - let skol_obligation_trait_ref = skol_obligation.trait_ref; - - let impl_substs = util::fresh_type_vars_for_impl(self.infcx, - obligation.cause.span, - impl_def_id); - - let impl_trait_ref = impl_trait_ref.subst(self.tcx(), - &impl_substs); - - let impl_trait_ref = - project::normalize_with_depth(self, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &impl_trait_ref); - - debug!("match_impl(impl_def_id={:?}, obligation={:?}, \ - impl_trait_ref={:?}, skol_obligation_trait_ref={:?})", - impl_def_id, - obligation, - impl_trait_ref, - skol_obligation_trait_ref); - - let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); - if let Err(e) = self.infcx.eq_trait_refs(false, - origin, - impl_trait_ref.value.clone(), - skol_obligation_trait_ref) { - debug!("match_impl: failed eq_trait_refs due to `{}`", e); - return Err(()); - } - - if let Err(e) = self.infcx.leak_check(&skol_map, snapshot) { - debug!("match_impl: failed leak check due to `{}`", e); - return Err(()); - } - - debug!("match_impl: success impl_substs={:?}", impl_substs); - Ok((Normalized { - value: impl_substs, - obligations: impl_trait_ref.obligations - }, skol_map)) - } - - fn fast_reject_trait_refs(&mut self, - obligation: &TraitObligation, - impl_trait_ref: &ty::TraitRef) - -> bool - { - // We can avoid creating type variables and doing the full - // substitution if we find that any of the input types, when - // simplified, do not match. - - obligation.predicate.0.input_types().iter() - .zip(impl_trait_ref.input_types()) - .any(|(&obligation_ty, &impl_ty)| { - let simplified_obligation_ty = - fast_reject::simplify_type(self.tcx(), obligation_ty, true); - let simplified_impl_ty = - fast_reject::simplify_type(self.tcx(), impl_ty, false); - - simplified_obligation_ty.is_some() && - simplified_impl_ty.is_some() && - simplified_obligation_ty != simplified_impl_ty - }) - } - - /// Normalize `where_clause_trait_ref` and try to match it against - /// `obligation`. If successful, return any predicates that - /// result from the normalization. Normalization is necessary - /// because where-clauses are stored in the parameter environment - /// unnormalized. - fn match_where_clause_trait_ref(&mut self, - obligation: &TraitObligation<'tcx>, - where_clause_trait_ref: ty::PolyTraitRef<'tcx>) - -> Result>,()> - { - self.match_poly_trait_ref(obligation, where_clause_trait_ref)?; - Ok(Vec::new()) - } - - /// Returns `Ok` if `poly_trait_ref` being true implies that the - /// obligation is satisfied. - fn match_poly_trait_ref(&self, - obligation: &TraitObligation<'tcx>, - poly_trait_ref: ty::PolyTraitRef<'tcx>) - -> Result<(),()> - { - debug!("match_poly_trait_ref: obligation={:?} poly_trait_ref={:?}", - obligation, - poly_trait_ref); - - let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); - match self.infcx.sub_poly_trait_refs(false, - origin, - poly_trait_ref, - obligation.predicate.to_poly_trait_ref()) { - Ok(()) => Ok(()), - Err(_) => Err(()), - } - } - - /////////////////////////////////////////////////////////////////////////// - // Miscellany - - fn match_fresh_trait_refs(&self, - previous: &ty::PolyTraitRef<'tcx>, - current: &ty::PolyTraitRef<'tcx>) - -> bool - { - let mut matcher = ty::_match::Match::new(self.tcx()); - matcher.relate(previous, current).is_ok() - } - - fn push_stack<'o,'s:'o>(&mut self, - previous_stack: TraitObligationStackList<'s, 'tcx>, - obligation: &'o TraitObligation<'tcx>) - -> TraitObligationStack<'o, 'tcx> - { - let fresh_trait_ref = - obligation.predicate.to_poly_trait_ref().fold_with(&mut self.freshener); - - TraitObligationStack { - obligation: obligation, - fresh_trait_ref: fresh_trait_ref, - previous: previous_stack, - } - } - - fn closure_trait_ref_unnormalized(&mut self, - obligation: &TraitObligation<'tcx>, - closure_def_id: DefId, - substs: &ty::ClosureSubsts<'tcx>) - -> ty::PolyTraitRef<'tcx> - { - let closure_type = self.infcx.closure_type(closure_def_id, substs); - let ty::Binder((trait_ref, _)) = - util::closure_trait_ref_and_return_type(self.tcx(), - obligation.predicate.def_id(), - obligation.predicate.0.self_ty(), // (1) - &closure_type.sig, - util::TupleArgumentsFlag::No); - // (1) Feels icky to skip the binder here, but OTOH we know - // that the self-type is an unboxed closure type and hence is - // in fact unparameterized (or at least does not reference any - // regions bound in the obligation). Still probably some - // refactoring could make this nicer. - - ty::Binder(trait_ref) - } - - fn closure_trait_ref(&mut self, - obligation: &TraitObligation<'tcx>, - closure_def_id: DefId, - substs: &ty::ClosureSubsts<'tcx>) - -> Normalized<'tcx, ty::PolyTraitRef<'tcx>> - { - let trait_ref = self.closure_trait_ref_unnormalized( - obligation, closure_def_id, substs); - - // A closure signature can contain associated types which - // must be normalized. - normalize_with_depth(self, - obligation.cause.clone(), - obligation.recursion_depth+1, - &trait_ref) - } - - /// Returns the obligations that are implied by instantiating an - /// impl or trait. The obligations are substituted and fully - /// normalized. This is used when confirming an impl or default - /// impl. - fn impl_or_trait_obligations(&mut self, - cause: ObligationCause<'tcx>, - recursion_depth: usize, - def_id: DefId, // of impl or trait - substs: &Substs<'tcx>, // for impl or trait - skol_map: infer::SkolemizationMap, - snapshot: &infer::CombinedSnapshot) - -> Vec> - { - debug!("impl_or_trait_obligations(def_id={:?})", def_id); - let tcx = self.tcx(); - - // To allow for one-pass evaluation of the nested obligation, - // each predicate must be preceded by the obligations required - // to normalize it. - // for example, if we have: - // impl> Foo for V where U::Item: Copy - // the impl will have the following predicates: - // ::Item = U, - // U: Iterator, U: Sized, - // V: Iterator, V: Sized, - // ::Item: Copy - // When we substitute, say, `V => IntoIter, U => $0`, the last - // obligation will normalize to `<$0 as Iterator>::Item = $1` and - // `$1: Copy`, so we must ensure the obligations are emitted in - // that order. - let predicates = tcx - .lookup_predicates(def_id) - .predicates.iter() - .flat_map(|predicate| { - let predicate = - normalize_with_depth(self, cause.clone(), recursion_depth, - &predicate.subst(tcx, substs)); - predicate.obligations.into_iter().chain( - Some(Obligation { - cause: cause.clone(), - recursion_depth: recursion_depth, - predicate: predicate.value - })) - }).collect(); - self.infcx().plug_leaks(skol_map, snapshot, &predicates) - } - - #[allow(unused_comparisons)] - fn derived_cause(&self, - obligation: &TraitObligation<'tcx>, - variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>) - -> ObligationCause<'tcx> - { - /*! - * Creates a cause for obligations that are derived from - * `obligation` by a recursive search (e.g., for a builtin - * bound, or eventually a `impl Foo for ..`). If `obligation` - * is itself a derived obligation, this is just a clone, but - * otherwise we create a "derived obligation" cause so as to - * keep track of the original root obligation for error - * reporting. - */ - - // NOTE(flaper87): As of now, it keeps track of the whole error - // chain. Ideally, we should have a way to configure this either - // by using -Z verbose or just a CLI argument. - if obligation.recursion_depth >= 0 { - let derived_cause = DerivedObligationCause { - parent_trait_ref: obligation.predicate.to_poly_trait_ref(), - parent_code: Rc::new(obligation.cause.code.clone()) - }; - let derived_code = variant(derived_cause); - ObligationCause::new(obligation.cause.span, obligation.cause.body_id, derived_code) - } else { - obligation.cause.clone() - } - } -} - -impl<'tcx> SelectionCache<'tcx> { - pub fn new() -> SelectionCache<'tcx> { - SelectionCache { - hashmap: RefCell::new(FnvHashMap()) - } - } -} - -impl<'tcx> EvaluationCache<'tcx> { - pub fn new() -> EvaluationCache<'tcx> { - EvaluationCache { - hashmap: RefCell::new(FnvHashMap()) - } - } -} - -impl<'o,'tcx> TraitObligationStack<'o,'tcx> { - fn list(&'o self) -> TraitObligationStackList<'o,'tcx> { - TraitObligationStackList::with(self) - } - - fn iter(&'o self) -> TraitObligationStackList<'o,'tcx> { - self.list() - } -} - -#[derive(Copy, Clone)] -struct TraitObligationStackList<'o,'tcx:'o> { - head: Option<&'o TraitObligationStack<'o,'tcx>> -} - -impl<'o,'tcx> TraitObligationStackList<'o,'tcx> { - fn empty() -> TraitObligationStackList<'o,'tcx> { - TraitObligationStackList { head: None } - } - - fn with(r: &'o TraitObligationStack<'o,'tcx>) -> TraitObligationStackList<'o,'tcx> { - TraitObligationStackList { head: Some(r) } - } -} - -impl<'o,'tcx> Iterator for TraitObligationStackList<'o,'tcx>{ - type Item = &'o TraitObligationStack<'o,'tcx>; - - fn next(&mut self) -> Option<&'o TraitObligationStack<'o,'tcx>> { - match self.head { - Some(o) => { - *self = o.previous; - Some(o) - } - None => None - } - } -} - -impl<'o,'tcx> fmt::Debug for TraitObligationStack<'o,'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "TraitObligationStack({:?})", self.obligation) - } -} - -impl EvaluationResult { - fn may_apply(&self) -> bool { - match *self { - EvaluatedToOk | - EvaluatedToAmbig | - EvaluatedToUnknown => true, - - EvaluatedToErr => false - } - } -} - -impl MethodMatchResult { - pub fn may_apply(&self) -> bool { - match *self { - MethodMatched(_) => true, - MethodAmbiguous(_) => true, - MethodDidNotMatch => false, - } - } -} diff --git a/src/librustc/middle/traits/specialize/mod.rs b/src/librustc/middle/traits/specialize/mod.rs deleted file mode 100644 index 088099d87b1..00000000000 --- a/src/librustc/middle/traits/specialize/mod.rs +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright 2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Logic and data structures related to impl specialization, explained in -// greater detail below. -// -// At the moment, this implementation support only the simple "chain" rule: -// If any two impls overlap, one must be a strict subset of the other. -// -// See traits/README.md for a bit more detail on how specialization -// fits together with the rest of the trait machinery. - -use super::{SelectionContext, FulfillmentContext}; -use super::util::{fresh_type_vars_for_impl, impl_trait_ref_and_oblig}; - -use middle::cstore::CrateStore; -use middle::def_id::DefId; -use middle::infer::{self, InferCtxt, TypeOrigin}; -use middle::region; -use middle::ty::subst::{Subst, Substs}; -use middle::traits::{self, ProjectionMode, ObligationCause, Normalized}; -use middle::ty::{self, TyCtxt}; -use syntax::codemap::DUMMY_SP; - -pub mod specialization_graph; - -/// Information pertinent to an overlapping impl error. -pub struct Overlap<'a, 'tcx: 'a> { - pub in_context: InferCtxt<'a, 'tcx>, - pub with_impl: DefId, - pub on_trait_ref: ty::TraitRef<'tcx>, -} - -/// Given a subst for the requested impl, translate it to a subst -/// appropriate for the actual item definition (whether it be in that impl, -/// a parent impl, or the trait). -/// When we have selected one impl, but are actually using item definitions from -/// a parent impl providing a default, we need a way to translate between the -/// type parameters of the two impls. Here the `source_impl` is the one we've -/// selected, and `source_substs` is a substitution of its generics (and -/// possibly some relevant `FnSpace` variables as well). And `target_node` is -/// the impl/trait we're actually going to get the definition from. The resulting -/// substitution will map from `target_node`'s generics to `source_impl`'s -/// generics as instantiated by `source_subst`. -/// -/// For example, consider the following scenario: -/// -/// ```rust -/// trait Foo { ... } -/// impl Foo for (T, U) { ... } // target impl -/// impl Foo for (V, V) { ... } // source impl -/// ``` -/// -/// Suppose we have selected "source impl" with `V` instantiated with `u32`. -/// This function will produce a substitution with `T` and `U` both mapping to `u32`. -/// -/// Where clauses add some trickiness here, because they can be used to "define" -/// an argument indirectly: -/// -/// ```rust -/// impl<'a, I, T: 'a> Iterator for Cloned -/// where I: Iterator, T: Clone -/// ``` -/// -/// In a case like this, the substitution for `T` is determined indirectly, -/// through associated type projection. We deal with such cases by using -/// *fulfillment* to relate the two impls, requiring that all projections are -/// resolved. -pub fn translate_substs<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, - source_impl: DefId, - source_substs: &'tcx Substs<'tcx>, - target_node: specialization_graph::Node) - -> &'tcx Substs<'tcx> { - let source_trait_ref = infcx.tcx - .impl_trait_ref(source_impl) - .unwrap() - .subst(infcx.tcx, &source_substs); - - // translate the Self and TyParam parts of the substitution, since those - // vary across impls - let target_substs = match target_node { - specialization_graph::Node::Impl(target_impl) => { - // no need to translate if we're targetting the impl we started with - if source_impl == target_impl { - return source_substs; - } - - fulfill_implication(infcx, source_trait_ref, target_impl).unwrap_or_else(|_| { - infcx.tcx - .sess - .bug("When translating substitutions for specialization, the expected \ - specializaiton failed to hold") - }) - } - specialization_graph::Node::Trait(..) => source_trait_ref.substs.clone(), - }; - - // directly inherent the method generics, since those do not vary across impls - infcx.tcx.mk_substs(target_substs.with_method_from_subst(source_substs)) -} - -/// Is impl1 a specialization of impl2? -/// -/// Specialization is determined by the sets of types to which the impls apply; -/// impl1 specializes impl2 if it applies to a subset of the types impl2 applies -/// to. -pub fn specializes(tcx: &TyCtxt, impl1_def_id: DefId, impl2_def_id: DefId) -> bool { - // The feature gate should prevent introducing new specializations, but not - // taking advantage of upstream ones. - if !tcx.sess.features.borrow().specialization && - (impl1_def_id.is_local() || impl2_def_id.is_local()) { - return false; - } - - // We determine whether there's a subset relationship by: - // - // - skolemizing impl1, - // - assuming the where clauses for impl1, - // - instantiating impl2 with fresh inference variables, - // - unifying, - // - attempting to prove the where clauses for impl2 - // - // The last three steps are encapsulated in `fulfill_implication`. - // - // See RFC 1210 for more details and justification. - - // Currently we do not allow e.g. a negative impl to specialize a positive one - if tcx.trait_impl_polarity(impl1_def_id) != tcx.trait_impl_polarity(impl2_def_id) { - return false; - } - - let mut infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables, ProjectionMode::Topmost); - - // create a parameter environment corresponding to a (skolemized) instantiation of impl1 - let scheme = tcx.lookup_item_type(impl1_def_id); - let predicates = tcx.lookup_predicates(impl1_def_id); - let mut penv = tcx.construct_parameter_environment(DUMMY_SP, - &scheme.generics, - &predicates, - region::DUMMY_CODE_EXTENT); - let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id) - .unwrap() - .subst(tcx, &penv.free_substs); - - // Normalize the trait reference, adding any obligations that arise into the impl1 assumptions - let Normalized { value: impl1_trait_ref, obligations: normalization_obligations } = { - let selcx = &mut SelectionContext::new(&infcx); - traits::normalize(selcx, ObligationCause::dummy(), &impl1_trait_ref) - }; - penv.caller_bounds.extend(normalization_obligations.into_iter().map(|o| o.predicate)); - - // Install the parameter environment, taking the predicates of impl1 as assumptions: - infcx.parameter_environment = penv; - - // Attempt to prove that impl2 applies, given all of the above. - fulfill_implication(&infcx, impl1_trait_ref, impl2_def_id).is_ok() -} - -/// Attempt to fulfill all obligations of `target_impl` after unification with -/// `source_trait_ref`. If successful, returns a substitution for *all* the -/// generics of `target_impl`, including both those needed to unify with -/// `source_trait_ref` and those whose identity is determined via a where -/// clause in the impl. -fn fulfill_implication<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, - source_trait_ref: ty::TraitRef<'tcx>, - target_impl: DefId) - -> Result, ()> { - infcx.commit_if_ok(|_| { - let selcx = &mut SelectionContext::new(&infcx); - let target_substs = fresh_type_vars_for_impl(&infcx, DUMMY_SP, target_impl); - let (target_trait_ref, obligations) = impl_trait_ref_and_oblig(selcx, - target_impl, - &target_substs); - - // do the impls unify? If not, no specialization. - if let Err(_) = infer::mk_eq_trait_refs(&infcx, - true, - TypeOrigin::Misc(DUMMY_SP), - source_trait_ref, - target_trait_ref) { - debug!("fulfill_implication: {:?} does not unify with {:?}", - source_trait_ref, - target_trait_ref); - return Err(()); - } - - // attempt to prove all of the predicates for impl2 given those for impl1 - // (which are packed up in penv) - - let mut fulfill_cx = FulfillmentContext::new(); - for oblig in obligations.into_iter() { - fulfill_cx.register_predicate_obligation(&infcx, oblig); - } - - if let Err(errors) = infer::drain_fulfillment_cx(&infcx, &mut fulfill_cx, &()) { - // no dice! - debug!("fulfill_implication: for impls on {:?} and {:?}, could not fulfill: {:?} given \ - {:?}", - source_trait_ref, - target_trait_ref, - errors, - infcx.parameter_environment.caller_bounds); - Err(()) - } else { - debug!("fulfill_implication: an impl for {:?} specializes {:?}", - source_trait_ref, - target_trait_ref); - - // Now resolve the *substitution* we built for the target earlier, replacing - // the inference variables inside with whatever we got from fulfillment. - Ok(infcx.resolve_type_vars_if_possible(&target_substs)) - } - }) -} diff --git a/src/librustc/middle/traits/specialize/specialization_graph.rs b/src/librustc/middle/traits/specialize/specialization_graph.rs deleted file mode 100644 index f2170f75a11..00000000000 --- a/src/librustc/middle/traits/specialize/specialization_graph.rs +++ /dev/null @@ -1,393 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::cell; -use std::rc::Rc; - -use super::{Overlap, specializes}; - -use middle::cstore::CrateStore; -use middle::def_id::DefId; -use middle::infer; -use middle::traits::{self, ProjectionMode}; -use middle::ty::{self, TyCtxt, ImplOrTraitItem, TraitDef, TypeFoldable}; -use syntax::ast::Name; -use util::nodemap::DefIdMap; - -/// A per-trait graph of impls in specialization order. At the moment, this -/// graph forms a tree rooted with the trait itself, with all other nodes -/// representing impls, and parent-child relationships representing -/// specializations. -/// -/// The graph provides two key services: -/// -/// - Construction, which implicitly checks for overlapping impls (i.e., impls -/// that overlap but where neither specializes the other -- an artifact of the -/// simple "chain" rule. -/// -/// - Parent extraction. In particular, the graph can give you the *immediate* -/// parents of a given specializing impl, which is needed for extracting -/// default items amongst other thigns. In the simple "chain" rule, every impl -/// has at most one parent. -pub struct Graph { - // all impls have a parent; the "root" impls have as their parent the def_id - // of the trait - parent: DefIdMap, - - // the "root" impls are found by looking up the trait's def_id. - children: DefIdMap>, -} - -impl Graph { - pub fn new() -> Graph { - Graph { - parent: Default::default(), - children: Default::default(), - } - } - - /// Insert a local impl into the specialization graph. If an existing impl - /// conflicts with it (has overlap, but neither specializes the other), - /// information about the area of overlap is returned in the `Err`. - pub fn insert<'a, 'tcx>(&mut self, - tcx: &'a TyCtxt<'tcx>, - impl_def_id: DefId) - -> Result<(), Overlap<'a, 'tcx>> { - assert!(impl_def_id.is_local()); - - let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); - let trait_def_id = trait_ref.def_id; - - debug!("insert({:?}): inserting TraitRef {:?} into specialization graph", - impl_def_id, trait_ref); - - // if the reference itself contains an earlier error (e.g., due to a - // resolution failure), then we just insert the impl at the top level of - // the graph and claim that there's no overlap (in order to supress - // bogus errors). - if trait_ref.references_error() { - debug!("insert: inserting dummy node for erroneous TraitRef {:?}, \ - impl_def_id={:?}, trait_def_id={:?}", - trait_ref, impl_def_id, trait_def_id); - - self.parent.insert(impl_def_id, trait_def_id); - self.children.entry(trait_def_id).or_insert(vec![]).push(impl_def_id); - return Ok(()); - } - - let mut parent = trait_def_id; - - // Ugly hack around borrowck limitations. Assigned only in the case - // where we bump downward an existing node in the graph. - let child_to_insert; - - 'descend: loop { - let mut possible_siblings = self.children.entry(parent).or_insert(vec![]); - - for slot in possible_siblings.iter_mut() { - let possible_sibling = *slot; - - let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, ProjectionMode::Topmost); - let overlap = traits::overlapping_impls(&infcx, possible_sibling, impl_def_id); - - if let Some(impl_header) = overlap { - let le = specializes(tcx, impl_def_id, possible_sibling); - let ge = specializes(tcx, possible_sibling, impl_def_id); - - if le && !ge { - debug!("descending as child of TraitRef {:?}", - tcx.impl_trait_ref(possible_sibling).unwrap()); - - // the impl specializes possible_sibling - parent = possible_sibling; - continue 'descend; - } else if ge && !le { - debug!("placing as parent of TraitRef {:?}", - tcx.impl_trait_ref(possible_sibling).unwrap()); - - // possible_sibling specializes the impl - *slot = impl_def_id; - self.parent.insert(impl_def_id, parent); - self.parent.insert(possible_sibling, impl_def_id); - // we have to defer the insertion, because we can't - // relinquish the borrow of `self.children` - child_to_insert = possible_sibling; - break 'descend; - } else { - // overlap, but no specialization; error out - return Err(Overlap { - with_impl: possible_sibling, - on_trait_ref: impl_header.trait_ref.unwrap(), - in_context: infcx, - }); - } - } - } - - // no overlap with any potential siblings, so add as a new sibling - debug!("placing as new sibling"); - self.parent.insert(impl_def_id, parent); - possible_siblings.push(impl_def_id); - return Ok(()); - } - - self.children.insert(impl_def_id, vec![child_to_insert]); - Ok(()) - } - - /// Insert cached metadata mapping from a child impl back to its parent. - pub fn record_impl_from_cstore(&mut self, parent: DefId, child: DefId) { - if self.parent.insert(child, parent).is_some() { - panic!("When recording an impl from the crate store, information about its parent \ - was already present."); - } - - self.children.entry(parent).or_insert(vec![]).push(child); - } - - /// The parent of a given impl, which is the def id of the trait when the - /// impl is a "specialization root". - pub fn parent(&self, child: DefId) -> DefId { - *self.parent.get(&child).unwrap() - } -} - -/// A node in the specialization graph is either an impl or a trait -/// definition; either can serve as a source of item definitions. -/// There is always exactly one trait definition node: the root. -#[derive(Debug, Copy, Clone)] -pub enum Node { - Impl(DefId), - Trait(DefId), -} - -impl Node { - pub fn is_from_trait(&self) -> bool { - match *self { - Node::Trait(..) => true, - _ => false, - } - } - - /// Iterate over the items defined directly by the given (impl or trait) node. - pub fn items<'a, 'tcx>(&self, tcx: &'a TyCtxt<'tcx>) -> NodeItems<'a, 'tcx> { - match *self { - Node::Impl(impl_def_id) => { - NodeItems::Impl { - tcx: tcx, - items: cell::Ref::map(tcx.impl_items.borrow(), - |impl_items| &impl_items[&impl_def_id]), - idx: 0, - } - } - Node::Trait(trait_def_id) => { - NodeItems::Trait { - items: tcx.trait_items(trait_def_id).clone(), - idx: 0, - } - } - } - } - - pub fn def_id(&self) -> DefId { - match *self { - Node::Impl(did) => did, - Node::Trait(did) => did, - } - } -} - -/// An iterator over the items defined within a trait or impl. -pub enum NodeItems<'a, 'tcx: 'a> { - Impl { - tcx: &'a TyCtxt<'tcx>, - items: cell::Ref<'a, Vec>, - idx: usize, - }, - Trait { - items: Rc>>, - idx: usize, - }, -} - -impl<'a, 'tcx> Iterator for NodeItems<'a, 'tcx> { - type Item = ImplOrTraitItem<'tcx>; - fn next(&mut self) -> Option> { - match *self { - NodeItems::Impl { tcx, ref items, ref mut idx } => { - let items_table = tcx.impl_or_trait_items.borrow(); - if *idx < items.len() { - let item_def_id = items[*idx].def_id(); - let item = items_table[&item_def_id].clone(); - *idx += 1; - Some(item) - } else { - None - } - } - NodeItems::Trait { ref items, ref mut idx } => { - if *idx < items.len() { - let item = items[*idx].clone(); - *idx += 1; - Some(item) - } else { - None - } - } - } - } -} - -pub struct Ancestors<'a, 'tcx: 'a> { - trait_def: &'a TraitDef<'tcx>, - current_source: Option, -} - -impl<'a, 'tcx> Iterator for Ancestors<'a, 'tcx> { - type Item = Node; - fn next(&mut self) -> Option { - let cur = self.current_source.take(); - if let Some(Node::Impl(cur_impl)) = cur { - let parent = self.trait_def.specialization_graph.borrow().parent(cur_impl); - if parent == self.trait_def.def_id() { - self.current_source = Some(Node::Trait(parent)); - } else { - self.current_source = Some(Node::Impl(parent)); - } - } - cur - } -} - -pub struct NodeItem { - pub node: Node, - pub item: T, -} - -impl NodeItem { - pub fn map U>(self, f: F) -> NodeItem { - NodeItem { - node: self.node, - item: f(self.item), - } - } -} - -pub struct TypeDefs<'a, 'tcx: 'a> { - // generally only invoked once or twice, so the box doesn't hurt - iter: Box>>> + 'a>, -} - -impl<'a, 'tcx> Iterator for TypeDefs<'a, 'tcx> { - type Item = NodeItem>>; - fn next(&mut self) -> Option { - self.iter.next() - } -} - -pub struct FnDefs<'a, 'tcx: 'a> { - // generally only invoked once or twice, so the box doesn't hurt - iter: Box>>> + 'a>, -} - -impl<'a, 'tcx> Iterator for FnDefs<'a, 'tcx> { - type Item = NodeItem>>; - fn next(&mut self) -> Option { - self.iter.next() - } -} - -pub struct ConstDefs<'a, 'tcx: 'a> { - // generally only invoked once or twice, so the box doesn't hurt - iter: Box>>> + 'a>, -} - -impl<'a, 'tcx> Iterator for ConstDefs<'a, 'tcx> { - type Item = NodeItem>>; - fn next(&mut self) -> Option { - self.iter.next() - } -} - -impl<'a, 'tcx> Ancestors<'a, 'tcx> { - /// Search the items from the given ancestors, returning each type definition - /// with the given name. - pub fn type_defs(self, tcx: &'a TyCtxt<'tcx>, name: Name) -> TypeDefs<'a, 'tcx> { - let iter = self.flat_map(move |node| { - node.items(tcx) - .filter_map(move |item| { - if let ty::TypeTraitItem(assoc_ty) = item { - if assoc_ty.name == name { - return Some(NodeItem { - node: node, - item: assoc_ty, - }); - } - } - None - }) - - }); - TypeDefs { iter: Box::new(iter) } - } - - /// Search the items from the given ancestors, returning each fn definition - /// with the given name. - pub fn fn_defs(self, tcx: &'a TyCtxt<'tcx>, name: Name) -> FnDefs<'a, 'tcx> { - let iter = self.flat_map(move |node| { - node.items(tcx) - .filter_map(move |item| { - if let ty::MethodTraitItem(method) = item { - if method.name == name { - return Some(NodeItem { - node: node, - item: method, - }); - } - } - None - }) - - }); - FnDefs { iter: Box::new(iter) } - } - - /// Search the items from the given ancestors, returning each const - /// definition with the given name. - pub fn const_defs(self, tcx: &'a TyCtxt<'tcx>, name: Name) -> ConstDefs<'a, 'tcx> { - let iter = self.flat_map(move |node| { - node.items(tcx) - .filter_map(move |item| { - if let ty::ConstTraitItem(konst) = item { - if konst.name == name { - return Some(NodeItem { - node: node, - item: konst, - }); - } - } - None - }) - - }); - ConstDefs { iter: Box::new(iter) } - } -} - -/// Walk up the specialization ancestors of a given impl, starting with that -/// impl itself. -pub fn ancestors<'a, 'tcx>(trait_def: &'a TraitDef<'tcx>, - start_from_impl: DefId) - -> Ancestors<'a, 'tcx> { - Ancestors { - trait_def: trait_def, - current_source: Some(Node::Impl(start_from_impl)), - } -} diff --git a/src/librustc/middle/traits/structural_impls.rs b/src/librustc/middle/traits/structural_impls.rs deleted file mode 100644 index 903b7c80baf..00000000000 --- a/src/librustc/middle/traits/structural_impls.rs +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright 2012-2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use middle::traits; -use middle::traits::project::Normalized; -use middle::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; - -use std::fmt; - -// structural impls for the structs in middle::traits - -impl<'tcx, T: fmt::Debug> fmt::Debug for Normalized<'tcx, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Normalized({:?},{:?})", - self.value, - self.obligations) - } -} - -impl<'tcx> fmt::Debug for traits::RegionObligation<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "RegionObligation(sub_region={:?}, sup_type={:?})", - self.sub_region, - self.sup_type) - } -} -impl<'tcx, O: fmt::Debug> fmt::Debug for traits::Obligation<'tcx, O> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Obligation(predicate={:?},depth={})", - self.predicate, - self.recursion_depth) - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::Vtable<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - super::VtableImpl(ref v) => - write!(f, "{:?}", v), - - super::VtableDefaultImpl(ref t) => - write!(f, "{:?}", t), - - super::VtableClosure(ref d) => - write!(f, "{:?}", d), - - super::VtableFnPointer(ref d) => - write!(f, "VtableFnPointer({:?})", d), - - super::VtableObject(ref d) => - write!(f, "{:?}", d), - - super::VtableParam(ref n) => - write!(f, "VtableParam({:?})", n), - - super::VtableBuiltin(ref d) => - write!(f, "{:?}", d) - } - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableImplData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "VtableImpl(impl_def_id={:?}, substs={:?}, nested={:?})", - self.impl_def_id, - self.substs, - self.nested) - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableClosureData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "VtableClosure(closure_def_id={:?}, substs={:?}, nested={:?})", - self.closure_def_id, - self.substs, - self.nested) - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableBuiltinData { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "VtableBuiltin(nested={:?})", self.nested) - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableDefaultImplData { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "VtableDefaultImplData(trait_def_id={:?}, nested={:?})", - self.trait_def_id, - self.nested) - } -} - -impl<'tcx> fmt::Debug for traits::VtableObjectData<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "VtableObject(upcast={:?}, vtable_base={})", - self.upcast_trait_ref, - self.vtable_base) - } -} - -impl<'tcx> fmt::Debug for traits::FulfillmentError<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "FulfillmentError({:?},{:?})", - self.obligation, - self.code) - } -} - -impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - super::CodeSelectionError(ref e) => write!(f, "{:?}", e), - super::CodeProjectionError(ref e) => write!(f, "{:?}", e), - super::CodeAmbiguity => write!(f, "Ambiguity") - } - } -} - -impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "MismatchedProjectionTypes({:?})", self.err) - } -} - -impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx, O> -{ - fn super_fold_with>(&self, folder: &mut F) -> Self { - traits::Obligation { - cause: self.cause.clone(), - recursion_depth: self.recursion_depth, - predicate: self.predicate.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.predicate.visit_with(visitor) - } -} - -impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableImplData<'tcx, N> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - let substs = self.substs.fold_with(folder); - traits::VtableImplData { - impl_def_id: self.impl_def_id, - substs: folder.tcx().mk_substs(substs), - nested: self.nested.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.substs.visit_with(visitor) || self.nested.visit_with(visitor) - } -} - -impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableClosureData<'tcx, N> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - traits::VtableClosureData { - closure_def_id: self.closure_def_id, - substs: self.substs.fold_with(folder), - nested: self.nested.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.substs.visit_with(visitor) || self.nested.visit_with(visitor) - } -} - -impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableDefaultImplData { - fn super_fold_with>(&self, folder: &mut F) -> Self { - traits::VtableDefaultImplData { - trait_def_id: self.trait_def_id, - nested: self.nested.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.nested.visit_with(visitor) - } -} - -impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableBuiltinData { - fn super_fold_with>(&self, folder: &mut F) -> Self { - traits::VtableBuiltinData { - nested: self.nested.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.nested.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - traits::VtableObjectData { - upcast_trait_ref: self.upcast_trait_ref.fold_with(folder), - vtable_base: self.vtable_base - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.upcast_trait_ref.visit_with(visitor) - } -} - -impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - match *self { - traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)), - traits::VtableDefaultImpl(ref t) => traits::VtableDefaultImpl(t.fold_with(folder)), - traits::VtableClosure(ref d) => { - traits::VtableClosure(d.fold_with(folder)) - } - traits::VtableFnPointer(ref d) => { - traits::VtableFnPointer(d.fold_with(folder)) - } - traits::VtableParam(ref n) => traits::VtableParam(n.fold_with(folder)), - traits::VtableBuiltin(ref d) => traits::VtableBuiltin(d.fold_with(folder)), - traits::VtableObject(ref d) => traits::VtableObject(d.fold_with(folder)), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - match *self { - traits::VtableImpl(ref v) => v.visit_with(visitor), - traits::VtableDefaultImpl(ref t) => t.visit_with(visitor), - traits::VtableClosure(ref d) => d.visit_with(visitor), - traits::VtableFnPointer(ref d) => d.visit_with(visitor), - traits::VtableParam(ref n) => n.visit_with(visitor), - traits::VtableBuiltin(ref d) => d.visit_with(visitor), - traits::VtableObject(ref d) => d.visit_with(visitor), - } - } -} - -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Normalized<'tcx, T> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - Normalized { - value: self.value.fold_with(folder), - obligations: self.obligations.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.value.visit_with(visitor) || self.obligations.visit_with(visitor) - } -} diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs deleted file mode 100644 index f9a1b09a93d..00000000000 --- a/src/librustc/middle/traits/util.rs +++ /dev/null @@ -1,508 +0,0 @@ -// Copyright 2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use middle::def_id::DefId; -use middle::infer::InferCtxt; -use middle::ty::subst::{Subst, Substs}; -use middle::ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef}; -use syntax::codemap::Span; -use util::common::ErrorReported; -use util::nodemap::FnvHashSet; - -use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext, Normalized}; - -struct PredicateSet<'a,'tcx:'a> { - tcx: &'a TyCtxt<'tcx>, - set: FnvHashSet>, -} - -impl<'a,'tcx> PredicateSet<'a,'tcx> { - fn new(tcx: &'a TyCtxt<'tcx>) -> PredicateSet<'a,'tcx> { - PredicateSet { tcx: tcx, set: FnvHashSet() } - } - - fn insert(&mut self, pred: &ty::Predicate<'tcx>) -> bool { - // We have to be careful here because we want - // - // for<'a> Foo<&'a int> - // - // and - // - // for<'b> Foo<&'b int> - // - // to be considered equivalent. So normalize all late-bound - // regions before we throw things into the underlying set. - let normalized_pred = match *pred { - ty::Predicate::Trait(ref data) => - ty::Predicate::Trait(self.tcx.anonymize_late_bound_regions(data)), - - ty::Predicate::Equate(ref data) => - ty::Predicate::Equate(self.tcx.anonymize_late_bound_regions(data)), - - ty::Predicate::RegionOutlives(ref data) => - ty::Predicate::RegionOutlives(self.tcx.anonymize_late_bound_regions(data)), - - ty::Predicate::TypeOutlives(ref data) => - ty::Predicate::TypeOutlives(self.tcx.anonymize_late_bound_regions(data)), - - ty::Predicate::Projection(ref data) => - ty::Predicate::Projection(self.tcx.anonymize_late_bound_regions(data)), - - ty::Predicate::WellFormed(data) => - ty::Predicate::WellFormed(data), - - ty::Predicate::ObjectSafe(data) => - ty::Predicate::ObjectSafe(data), - }; - self.set.insert(normalized_pred) - } -} - -/////////////////////////////////////////////////////////////////////////// -// `Elaboration` iterator -/////////////////////////////////////////////////////////////////////////// - -/// "Elaboration" is the process of identifying all the predicates that -/// are implied by a source predicate. Currently this basically means -/// walking the "supertraits" and other similar assumptions. For -/// example, if we know that `T : Ord`, the elaborator would deduce -/// that `T : PartialOrd` holds as well. Similarly, if we have `trait -/// Foo : 'static`, and we know that `T : Foo`, then we know that `T : -/// 'static`. -pub struct Elaborator<'cx, 'tcx:'cx> { - tcx: &'cx TyCtxt<'tcx>, - stack: Vec>, - visited: PredicateSet<'cx,'tcx>, -} - -pub fn elaborate_trait_ref<'cx, 'tcx>( - tcx: &'cx TyCtxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>) - -> Elaborator<'cx, 'tcx> -{ - elaborate_predicates(tcx, vec![trait_ref.to_predicate()]) -} - -pub fn elaborate_trait_refs<'cx, 'tcx>( - tcx: &'cx TyCtxt<'tcx>, - trait_refs: &[ty::PolyTraitRef<'tcx>]) - -> Elaborator<'cx, 'tcx> -{ - let predicates = trait_refs.iter() - .map(|trait_ref| trait_ref.to_predicate()) - .collect(); - elaborate_predicates(tcx, predicates) -} - -pub fn elaborate_predicates<'cx, 'tcx>( - tcx: &'cx TyCtxt<'tcx>, - mut predicates: Vec>) - -> Elaborator<'cx, 'tcx> -{ - let mut visited = PredicateSet::new(tcx); - predicates.retain(|pred| visited.insert(pred)); - Elaborator { tcx: tcx, stack: predicates, visited: visited } -} - -impl<'cx, 'tcx> Elaborator<'cx, 'tcx> { - pub fn filter_to_traits(self) -> FilterToTraits> { - FilterToTraits::new(self) - } - - fn push(&mut self, predicate: &ty::Predicate<'tcx>) { - match *predicate { - ty::Predicate::Trait(ref data) => { - // Predicates declared on the trait. - let predicates = self.tcx.lookup_super_predicates(data.def_id()); - - let mut predicates: Vec<_> = - predicates.predicates - .iter() - .map(|p| p.subst_supertrait(self.tcx, &data.to_poly_trait_ref())) - .collect(); - - debug!("super_predicates: data={:?} predicates={:?}", - data, predicates); - - // Only keep those bounds that we haven't already - // seen. This is necessary to prevent infinite - // recursion in some cases. One common case is when - // people define `trait Sized: Sized { }` rather than `trait - // Sized { }`. - predicates.retain(|r| self.visited.insert(r)); - - self.stack.extend(predicates); - } - ty::Predicate::WellFormed(..) => { - // Currently, we do not elaborate WF predicates, - // although we easily could. - } - ty::Predicate::ObjectSafe(..) => { - // Currently, we do not elaborate object-safe - // predicates. - } - ty::Predicate::Equate(..) => { - // Currently, we do not "elaborate" predicates like - // `X == Y`, though conceivably we might. For example, - // `&X == &Y` implies that `X == Y`. - } - ty::Predicate::Projection(..) => { - // Nothing to elaborate in a projection predicate. - } - ty::Predicate::RegionOutlives(..) | - ty::Predicate::TypeOutlives(..) => { - // Currently, we do not "elaborate" predicates like - // `'a : 'b` or `T : 'a`. We could conceivably do - // more here. For example, - // - // &'a int : 'b - // - // implies that - // - // 'a : 'b - // - // and we could get even more if we took WF - // constraints into account. For example, - // - // &'a &'b int : 'c - // - // implies that - // - // 'b : 'a - // 'a : 'c - } - } - } -} - -impl<'cx, 'tcx> Iterator for Elaborator<'cx, 'tcx> { - type Item = ty::Predicate<'tcx>; - - fn next(&mut self) -> Option> { - // Extract next item from top-most stack frame, if any. - let next_predicate = match self.stack.pop() { - Some(predicate) => predicate, - None => { - // No more stack frames. Done. - return None; - } - }; - self.push(&next_predicate); - return Some(next_predicate); - } -} - -/////////////////////////////////////////////////////////////////////////// -// Supertrait iterator -/////////////////////////////////////////////////////////////////////////// - -pub type Supertraits<'cx, 'tcx> = FilterToTraits>; - -pub fn supertraits<'cx, 'tcx>(tcx: &'cx TyCtxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>) - -> Supertraits<'cx, 'tcx> -{ - elaborate_trait_ref(tcx, trait_ref).filter_to_traits() -} - -pub fn transitive_bounds<'cx, 'tcx>(tcx: &'cx TyCtxt<'tcx>, - bounds: &[ty::PolyTraitRef<'tcx>]) - -> Supertraits<'cx, 'tcx> -{ - elaborate_trait_refs(tcx, bounds).filter_to_traits() -} - -/////////////////////////////////////////////////////////////////////////// -// Iterator over def-ids of supertraits - -pub struct SupertraitDefIds<'cx, 'tcx:'cx> { - tcx: &'cx TyCtxt<'tcx>, - stack: Vec, - visited: FnvHashSet, -} - -pub fn supertrait_def_ids<'cx, 'tcx>(tcx: &'cx TyCtxt<'tcx>, - trait_def_id: DefId) - -> SupertraitDefIds<'cx, 'tcx> -{ - SupertraitDefIds { - tcx: tcx, - stack: vec![trait_def_id], - visited: Some(trait_def_id).into_iter().collect(), - } -} - -impl<'cx, 'tcx> Iterator for SupertraitDefIds<'cx, 'tcx> { - type Item = DefId; - - fn next(&mut self) -> Option { - let def_id = match self.stack.pop() { - Some(def_id) => def_id, - None => { return None; } - }; - - let predicates = self.tcx.lookup_super_predicates(def_id); - let visited = &mut self.visited; - self.stack.extend( - predicates.predicates - .iter() - .filter_map(|p| p.to_opt_poly_trait_ref()) - .map(|t| t.def_id()) - .filter(|&super_def_id| visited.insert(super_def_id))); - Some(def_id) - } -} - -/////////////////////////////////////////////////////////////////////////// -// Other -/////////////////////////////////////////////////////////////////////////// - -/// A filter around an iterator of predicates that makes it yield up -/// just trait references. -pub struct FilterToTraits { - base_iterator: I -} - -impl FilterToTraits { - fn new(base: I) -> FilterToTraits { - FilterToTraits { base_iterator: base } - } -} - -impl<'tcx,I:Iterator>> Iterator for FilterToTraits { - type Item = ty::PolyTraitRef<'tcx>; - - fn next(&mut self) -> Option> { - loop { - match self.base_iterator.next() { - None => { - return None; - } - Some(ty::Predicate::Trait(data)) => { - return Some(data.to_poly_trait_ref()); - } - Some(_) => { - } - } - } - } -} - -/////////////////////////////////////////////////////////////////////////// -// Other -/////////////////////////////////////////////////////////////////////////// - -/// Instantiate all bound parameters of the impl with the given substs, -/// returning the resulting trait ref and all obligations that arise. -/// The obligations are closed under normalization. -pub fn impl_trait_ref_and_oblig<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, - impl_def_id: DefId, - impl_substs: &Substs<'tcx>) - -> (ty::TraitRef<'tcx>, - Vec>) -{ - let impl_trait_ref = - selcx.tcx().impl_trait_ref(impl_def_id).unwrap(); - let impl_trait_ref = - impl_trait_ref.subst(selcx.tcx(), impl_substs); - let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } = - super::normalize(selcx, ObligationCause::dummy(), &impl_trait_ref); - - let predicates = selcx.tcx().lookup_predicates(impl_def_id); - let predicates = predicates.instantiate(selcx.tcx(), impl_substs); - let Normalized { value: predicates, obligations: normalization_obligations2 } = - super::normalize(selcx, ObligationCause::dummy(), &predicates); - let impl_obligations = - predicates_for_generics(ObligationCause::dummy(), 0, &predicates); - - let impl_obligations: Vec<_> = - impl_obligations.into_iter() - .chain(normalization_obligations1) - .chain(normalization_obligations2) - .collect(); - - (impl_trait_ref, impl_obligations) -} - -// determine the `self` type, using fresh variables for all variables -// declared on the impl declaration e.g., `impl for Box<[(A,B)]>` -// would return ($0, $1) where $0 and $1 are freshly instantiated type -// variables. -pub fn fresh_type_vars_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, - span: Span, - impl_def_id: DefId) - -> Substs<'tcx> -{ - let tcx = infcx.tcx; - let impl_generics = tcx.lookup_item_type(impl_def_id).generics; - infcx.fresh_substs_for_generics(span, &impl_generics) -} - -/// See `super::obligations_for_generics` -pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>, - recursion_depth: usize, - generic_bounds: &ty::InstantiatedPredicates<'tcx>) - -> Vec> -{ - debug!("predicates_for_generics(generic_bounds={:?})", - generic_bounds); - - generic_bounds.predicates.iter().map(|predicate| { - Obligation { cause: cause.clone(), - recursion_depth: recursion_depth, - predicate: predicate.clone() } - }).collect() -} - -pub fn trait_ref_for_builtin_bound<'tcx>( - tcx: &TyCtxt<'tcx>, - builtin_bound: ty::BuiltinBound, - param_ty: Ty<'tcx>) - -> Result, ErrorReported> -{ - match tcx.lang_items.from_builtin_kind(builtin_bound) { - Ok(def_id) => { - Ok(ty::TraitRef { - def_id: def_id, - substs: tcx.mk_substs(Substs::empty().with_self_ty(param_ty)) - }) - } - Err(e) => { - tcx.sess.err(&e); - Err(ErrorReported) - } - } -} - -pub fn predicate_for_trait_ref<'tcx>( - cause: ObligationCause<'tcx>, - trait_ref: ty::TraitRef<'tcx>, - recursion_depth: usize) - -> PredicateObligation<'tcx> -{ - Obligation { - cause: cause, - recursion_depth: recursion_depth, - predicate: trait_ref.to_predicate(), - } -} - -pub fn predicate_for_trait_def<'tcx>( - tcx: &TyCtxt<'tcx>, - cause: ObligationCause<'tcx>, - trait_def_id: DefId, - recursion_depth: usize, - param_ty: Ty<'tcx>, - ty_params: Vec>) - -> PredicateObligation<'tcx> -{ - let trait_ref = ty::TraitRef { - def_id: trait_def_id, - substs: tcx.mk_substs(Substs::new_trait(ty_params, vec![], param_ty)) - }; - predicate_for_trait_ref(cause, trait_ref, recursion_depth) -} - -pub fn predicate_for_builtin_bound<'tcx>( - tcx: &TyCtxt<'tcx>, - cause: ObligationCause<'tcx>, - builtin_bound: ty::BuiltinBound, - recursion_depth: usize, - param_ty: Ty<'tcx>) - -> Result, ErrorReported> -{ - let trait_ref = trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty)?; - Ok(predicate_for_trait_ref(cause, trait_ref, recursion_depth)) -} - -/// Cast a trait reference into a reference to one of its super -/// traits; returns `None` if `target_trait_def_id` is not a -/// supertrait. -pub fn upcast<'tcx>(tcx: &TyCtxt<'tcx>, - source_trait_ref: ty::PolyTraitRef<'tcx>, - target_trait_def_id: DefId) - -> Vec> -{ - if source_trait_ref.def_id() == target_trait_def_id { - return vec![source_trait_ref]; // shorcut the most common case - } - - supertraits(tcx, source_trait_ref) - .filter(|r| r.def_id() == target_trait_def_id) - .collect() -} - -/// Given a trait `trait_ref`, returns the number of vtable entries -/// that come from `trait_ref`, excluding its supertraits. Used in -/// computing the vtable base for an upcast trait of a trait object. -pub fn count_own_vtable_entries<'tcx>(tcx: &TyCtxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>) - -> usize { - let mut entries = 0; - // Count number of methods and add them to the total offset. - // Skip over associated types and constants. - for trait_item in &tcx.trait_items(trait_ref.def_id())[..] { - if let ty::MethodTraitItem(_) = *trait_item { - entries += 1; - } - } - entries -} - -/// Given an upcast trait object described by `object`, returns the -/// index of the method `method_def_id` (which should be part of -/// `object.upcast_trait_ref`) within the vtable for `object`. -pub fn get_vtable_index_of_object_method<'tcx>(tcx: &TyCtxt<'tcx>, - object: &super::VtableObjectData<'tcx>, - method_def_id: DefId) -> usize { - // Count number of methods preceding the one we are selecting and - // add them to the total offset. - // Skip over associated types and constants. - let mut entries = object.vtable_base; - for trait_item in &tcx.trait_items(object.upcast_trait_ref.def_id())[..] { - if trait_item.def_id() == method_def_id { - // The item with the ID we were given really ought to be a method. - assert!(match *trait_item { - ty::MethodTraitItem(_) => true, - _ => false - }); - - return entries; - } - if let ty::MethodTraitItem(_) = *trait_item { - entries += 1; - } - } - - tcx.sess.bug(&format!("get_vtable_index_of_object_method: {:?} was not found", - method_def_id)); -} - -pub enum TupleArgumentsFlag { Yes, No } - -pub fn closure_trait_ref_and_return_type<'tcx>( - tcx: &TyCtxt<'tcx>, - fn_trait_def_id: DefId, - self_ty: Ty<'tcx>, - sig: &ty::PolyFnSig<'tcx>, - tuple_arguments: TupleArgumentsFlag) - -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)> -{ - let arguments_tuple = match tuple_arguments { - TupleArgumentsFlag::No => sig.0.inputs[0], - TupleArgumentsFlag::Yes => tcx.mk_tup(sig.0.inputs.to_vec()), - }; - let trait_substs = Substs::new_trait(vec![arguments_tuple], vec![], self_ty); - let trait_ref = ty::TraitRef { - def_id: fn_trait_def_id, - substs: tcx.mk_substs(trait_substs), - }; - ty::Binder((trait_ref, sig.0.output.unwrap_or(tcx.mk_nil()))) -} diff --git a/src/librustc/middle/ty/_match.rs b/src/librustc/middle/ty/_match.rs deleted file mode 100644 index fe54334da3d..00000000000 --- a/src/librustc/middle/ty/_match.rs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use middle::ty::{self, Ty, TyCtxt}; -use middle::ty::error::TypeError; -use middle::ty::relate::{self, Relate, TypeRelation, RelateResult}; - -/// A type "A" *matches* "B" if the fresh types in B could be -/// substituted with values so as to make it equal to A. Matching is -/// intended to be used only on freshened types, and it basically -/// indicates if the non-freshened versions of A and B could have been -/// unified. -/// -/// It is only an approximation. If it yields false, unification would -/// definitely fail, but a true result doesn't mean unification would -/// succeed. This is because we don't track the "side-constraints" on -/// type variables, nor do we track if the same freshened type appears -/// more than once. To some extent these approximations could be -/// fixed, given effort. -/// -/// Like subtyping, matching is really a binary relation, so the only -/// important thing about the result is Ok/Err. Also, matching never -/// affects any type variables or unification state. -pub struct Match<'a, 'tcx: 'a> { - tcx: &'a TyCtxt<'tcx> -} - -impl<'a, 'tcx> Match<'a, 'tcx> { - pub fn new(tcx: &'a TyCtxt<'tcx>) -> Match<'a, 'tcx> { - Match { tcx: tcx } - } -} - -impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Match<'a, 'tcx> { - fn tag(&self) -> &'static str { "Match" } - fn tcx(&self) -> &'a TyCtxt<'tcx> { self.tcx } - fn a_is_expected(&self) -> bool { true } // irrelevant - - fn relate_with_variance>(&mut self, - _: ty::Variance, - a: &T, - b: &T) - -> RelateResult<'tcx, T> - { - self.relate(a, b) - } - - fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> { - debug!("{}.regions({:?}, {:?})", - self.tag(), - a, - b); - Ok(a) - } - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - debug!("{}.tys({:?}, {:?})", self.tag(), - a, b); - if a == b { return Ok(a); } - - match (&a.sty, &b.sty) { - (_, &ty::TyInfer(ty::FreshTy(_))) | - (_, &ty::TyInfer(ty::FreshIntTy(_))) | - (_, &ty::TyInfer(ty::FreshFloatTy(_))) => { - Ok(a) - } - - (&ty::TyInfer(_), _) | - (_, &ty::TyInfer(_)) => { - Err(TypeError::Sorts(relate::expected_found(self, &a, &b))) - } - - (&ty::TyError, _) | (_, &ty::TyError) => { - Ok(self.tcx().types.err) - } - - _ => { - relate::super_relate_tys(self, a, b) - } - } - } - - fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) - -> RelateResult<'tcx, ty::Binder> - where T: Relate<'a,'tcx> - { - Ok(ty::Binder(self.relate(a.skip_binder(), b.skip_binder())?)) - } -} diff --git a/src/librustc/middle/ty/adjustment.rs b/src/librustc/middle/ty/adjustment.rs deleted file mode 100644 index e4c293a74e8..00000000000 --- a/src/librustc/middle/ty/adjustment.rs +++ /dev/null @@ -1,265 +0,0 @@ -// Copyright 2012-2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub use self::AutoAdjustment::*; -pub use self::AutoRef::*; - -use middle::ty::{self, Ty, TyCtxt, TypeAndMut, TypeFoldable}; -use middle::ty::LvaluePreference::{NoPreference}; - -use syntax::ast; -use syntax::codemap::Span; - -use rustc_front::hir; - -#[derive(Copy, Clone)] -pub enum AutoAdjustment<'tcx> { - AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type - AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer - AdjustMutToConstPointer, // go from a mut raw pointer to a const raw pointer - AdjustDerefRef(AutoDerefRef<'tcx>), -} - -/// Represents coercing a pointer to a different kind of pointer - where 'kind' -/// here means either or both of raw vs borrowed vs unique and fat vs thin. -/// -/// We transform pointers by following the following steps in order: -/// 1. Deref the pointer `self.autoderefs` times (may be 0). -/// 2. If `autoref` is `Some(_)`, then take the address and produce either a -/// `&` or `*` pointer. -/// 3. If `unsize` is `Some(_)`, then apply the unsize transformation, -/// which will do things like convert thin pointers to fat -/// pointers, or convert structs containing thin pointers to -/// structs containing fat pointers, or convert between fat -/// pointers. We don't store the details of how the transform is -/// done (in fact, we don't know that, because it might depend on -/// the precise type parameters). We just store the target -/// type. Trans figures out what has to be done at monomorphization -/// time based on the precise source/target type at hand. -/// -/// To make that more concrete, here are some common scenarios: -/// -/// 1. The simplest cases are where the pointer is not adjusted fat vs thin. -/// Here the pointer will be dereferenced N times (where a dereference can -/// happen to raw or borrowed pointers or any smart pointer which implements -/// Deref, including Box<_>). The number of dereferences is given by -/// `autoderefs`. It can then be auto-referenced zero or one times, indicated -/// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is -/// None. -/// -/// 2. A thin-to-fat coercon involves unsizing the underlying data. We start -/// with a thin pointer, deref a number of times, unsize the underlying data, -/// then autoref. The 'unsize' phase may change a fixed length array to a -/// dynamically sized one, a concrete object to a trait object, or statically -/// sized struct to a dyncamically sized one. E.g., &[i32; 4] -> &[i32] is -/// represented by: -/// -/// ``` -/// AutoDerefRef { -/// autoderefs: 1, // &[i32; 4] -> [i32; 4] -/// autoref: Some(AutoPtr), // [i32] -> &[i32] -/// unsize: Some([i32]), // [i32; 4] -> [i32] -/// } -/// ``` -/// -/// Note that for a struct, the 'deep' unsizing of the struct is not recorded. -/// E.g., `struct Foo { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]> -/// The autoderef and -ref are the same as in the above example, but the type -/// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about -/// the underlying conversions from `[i32; 4]` to `[i32]`. -/// -/// 3. Coercing a `Box` to `Box` is an interesting special case. In -/// that case, we have the pointer we need coming in, so there are no -/// autoderefs, and no autoref. Instead we just do the `Unsize` transformation. -/// At some point, of course, `Box` should move out of the compiler, in which -/// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> -> -/// Box<[i32]> is represented by: -/// -/// ``` -/// AutoDerefRef { -/// autoderefs: 0, -/// autoref: None, -/// unsize: Some(Box<[i32]>), -/// } -/// ``` -#[derive(Copy, Clone)] -pub struct AutoDerefRef<'tcx> { - /// Step 1. Apply a number of dereferences, producing an lvalue. - pub autoderefs: usize, - - /// Step 2. Optionally produce a pointer/reference from the value. - pub autoref: Option>, - - /// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to - /// `&[T]`. The stored type is the target pointer type. Note that - /// the source could be a thin or fat pointer. - pub unsize: Option>, -} - -impl<'tcx> AutoAdjustment<'tcx> { - pub fn is_identity(&self) -> bool { - match *self { - AdjustReifyFnPointer | - AdjustUnsafeFnPointer | - AdjustMutToConstPointer => false, - AdjustDerefRef(ref r) => r.is_identity(), - } - } -} -impl<'tcx> AutoDerefRef<'tcx> { - pub fn is_identity(&self) -> bool { - self.autoderefs == 0 && self.unsize.is_none() && self.autoref.is_none() - } -} - - -#[derive(Copy, Clone, PartialEq, Debug)] -pub enum AutoRef<'tcx> { - /// Convert from T to &T. - AutoPtr(&'tcx ty::Region, hir::Mutability), - - /// Convert from T to *T. - /// Value to thin pointer. - AutoUnsafe(hir::Mutability), -} - -#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] -pub enum CustomCoerceUnsized { - /// Records the index of the field being coerced. - Struct(usize) -} - -impl<'tcx> ty::TyS<'tcx> { - /// See `expr_ty_adjusted` - pub fn adjust(&'tcx self, cx: &TyCtxt<'tcx>, - span: Span, - expr_id: ast::NodeId, - adjustment: Option<&AutoAdjustment<'tcx>>, - mut method_type: F) - -> Ty<'tcx> where - F: FnMut(ty::MethodCall) -> Option>, - { - if let ty::TyError = self.sty { - return self; - } - - return match adjustment { - Some(adjustment) => { - match *adjustment { - AdjustReifyFnPointer => { - match self.sty { - ty::TyFnDef(_, _, b) => { - cx.mk_ty(ty::TyFnPtr(b)) - } - _ => { - cx.sess.bug( - &format!("AdjustReifyFnPointer adjustment on non-fn-item: \ - {:?}", self)); - } - } - } - - AdjustUnsafeFnPointer => { - match self.sty { - ty::TyFnPtr(b) => cx.safe_to_unsafe_fn_ty(b), - ref b => { - cx.sess.bug( - &format!("AdjustUnsafeFnPointer adjustment on non-fn-ptr: \ - {:?}", - b)); - } - } - } - - AdjustMutToConstPointer => { - match self.sty { - ty::TyRawPtr(mt) => cx.mk_ptr(ty::TypeAndMut { - ty: mt.ty, - mutbl: hir::MutImmutable - }), - ref b => { - cx.sess.bug( - &format!("AdjustMutToConstPointer on non-raw-ptr: \ - {:?}", - b)); - } - } - } - - AdjustDerefRef(ref adj) => { - let mut adjusted_ty = self; - - if !adjusted_ty.references_error() { - for i in 0..adj.autoderefs { - adjusted_ty = - adjusted_ty.adjust_for_autoderef(cx, - expr_id, - span, - i as u32, - &mut method_type); - } - } - - if let Some(target) = adj.unsize { - target - } else { - adjusted_ty.adjust_for_autoref(cx, adj.autoref) - } - } - } - } - None => self - }; - } - - pub fn adjust_for_autoderef(&'tcx self, - cx: &TyCtxt<'tcx>, - expr_id: ast::NodeId, - expr_span: Span, - autoderef: u32, // how many autoderefs so far? - mut method_type: F) - -> Ty<'tcx> where - F: FnMut(ty::MethodCall) -> Option>, - { - let method_call = ty::MethodCall::autoderef(expr_id, autoderef); - let mut adjusted_ty = self; - if let Some(method_ty) = method_type(method_call) { - // Method calls always have all late-bound regions - // fully instantiated. - let fn_ret = cx.no_late_bound_regions(&method_ty.fn_ret()).unwrap(); - adjusted_ty = fn_ret.unwrap(); - } - match adjusted_ty.builtin_deref(true, NoPreference) { - Some(mt) => mt.ty, - None => { - cx.sess.span_bug( - expr_span, - &format!("the {}th autoderef failed: {}", - autoderef, - adjusted_ty) - ); - } - } - } - - pub fn adjust_for_autoref(&'tcx self, cx: &TyCtxt<'tcx>, - autoref: Option>) - -> Ty<'tcx> { - match autoref { - None => self, - Some(AutoPtr(r, m)) => { - cx.mk_ref(r, TypeAndMut { ty: self, mutbl: m }) - } - Some(AutoUnsafe(m)) => { - cx.mk_ptr(TypeAndMut { ty: self, mutbl: m }) - } - } - } -} diff --git a/src/librustc/middle/ty/cast.rs b/src/librustc/middle/ty/cast.rs deleted file mode 100644 index b25d6e0476d..00000000000 --- a/src/librustc/middle/ty/cast.rs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Helpers for handling cast expressions, used in both -// typeck and trans. - -use middle::ty::{self, Ty}; - -use syntax::ast; - -/// Types that are represented as ints. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum IntTy { - U(ast::UintTy), - I, - CEnum, - Bool, - Char -} - -// Valid types for the result of a non-coercion cast -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum CastTy<'tcx> { - /// Various types that are represented as ints and handled mostly - /// in the same way, merged for easier matching. - Int(IntTy), - /// Floating-Point types - Float, - /// Function Pointers - FnPtr, - /// Raw pointers - Ptr(&'tcx ty::TypeAndMut<'tcx>), - /// References - RPtr(&'tcx ty::TypeAndMut<'tcx>), -} - -/// Cast Kind. See RFC 401 (or librustc_typeck/check/cast.rs) -#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)] -pub enum CastKind { - CoercionCast, - PtrPtrCast, - PtrAddrCast, - AddrPtrCast, - NumericCast, - EnumCast, - PrimIntCast, - U8CharCast, - ArrayPtrCast, - FnPtrPtrCast, - FnPtrAddrCast -} - -impl<'tcx> CastTy<'tcx> { - pub fn from_ty(t: Ty<'tcx>) -> Option> { - match t.sty { - ty::TyBool => Some(CastTy::Int(IntTy::Bool)), - ty::TyChar => Some(CastTy::Int(IntTy::Char)), - ty::TyInt(_) => Some(CastTy::Int(IntTy::I)), - ty::TyUint(u) => Some(CastTy::Int(IntTy::U(u))), - ty::TyFloat(_) => Some(CastTy::Float), - ty::TyEnum(d,_) if d.is_payloadfree() => - Some(CastTy::Int(IntTy::CEnum)), - ty::TyRawPtr(ref mt) => Some(CastTy::Ptr(mt)), - ty::TyRef(_, ref mt) => Some(CastTy::RPtr(mt)), - ty::TyFnPtr(..) => Some(CastTy::FnPtr), - _ => None, - } - } -} diff --git a/src/librustc/middle/ty/contents.rs b/src/librustc/middle/ty/contents.rs deleted file mode 100644 index 47a15a14b41..00000000000 --- a/src/librustc/middle/ty/contents.rs +++ /dev/null @@ -1,267 +0,0 @@ -// Copyright 2012-2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use middle::def_id::{DefId}; -use middle::ty::{self, Ty, TyCtxt}; -use util::common::MemoizationMap; -use util::nodemap::FnvHashMap; - -use std::fmt; -use std::ops; - -use syntax::ast; - -/// Type contents is how the type checker reasons about kinds. -/// They track what kinds of things are found within a type. You can -/// think of them as kind of an "anti-kind". They track the kinds of values -/// and thinks that are contained in types. Having a larger contents for -/// a type tends to rule that type *out* from various kinds. For example, -/// a type that contains a reference is not sendable. -/// -/// The reason we compute type contents and not kinds is that it is -/// easier for me (nmatsakis) to think about what is contained within -/// a type than to think about what is *not* contained within a type. -#[derive(Clone, Copy)] -pub struct TypeContents { - pub bits: u64 -} - -macro_rules! def_type_content_sets { - (mod $mname:ident { $($name:ident = $bits:expr),+ }) => { - #[allow(non_snake_case)] - mod $mname { - use super::TypeContents; - $( - #[allow(non_upper_case_globals)] - pub const $name: TypeContents = TypeContents { bits: $bits }; - )+ - } - } -} - -def_type_content_sets! { - mod TC { - None = 0b0000_0000__0000_0000__0000, - - // Things that are interior to the value (first nibble): - InteriorUnsafe = 0b0000_0000__0000_0000__0010, - InteriorParam = 0b0000_0000__0000_0000__0100, - // InteriorAll = 0b00000000__00000000__1111, - - // Things that are owned by the value (second and third nibbles): - OwnsOwned = 0b0000_0000__0000_0001__0000, - OwnsDtor = 0b0000_0000__0000_0010__0000, - OwnsAll = 0b0000_0000__1111_1111__0000, - - // Things that mean drop glue is necessary - NeedsDrop = 0b0000_0000__0000_0111__0000, - - // All bits - All = 0b1111_1111__1111_1111__1111 - } -} - -impl TypeContents { - pub fn when(&self, cond: bool) -> TypeContents { - if cond {*self} else {TC::None} - } - - pub fn intersects(&self, tc: TypeContents) -> bool { - (self.bits & tc.bits) != 0 - } - - pub fn owns_owned(&self) -> bool { - self.intersects(TC::OwnsOwned) - } - - pub fn interior_param(&self) -> bool { - self.intersects(TC::InteriorParam) - } - - pub fn interior_unsafe(&self) -> bool { - self.intersects(TC::InteriorUnsafe) - } - - pub fn needs_drop(&self, _: &TyCtxt) -> bool { - self.intersects(TC::NeedsDrop) - } - - /// Includes only those bits that still apply when indirected through a `Box` pointer - pub fn owned_pointer(&self) -> TypeContents { - TC::OwnsOwned | (*self & TC::OwnsAll) - } - - pub fn union(v: &[T], mut f: F) -> TypeContents where - F: FnMut(&T) -> TypeContents, - { - v.iter().fold(TC::None, |tc, ty| tc | f(ty)) - } - - pub fn has_dtor(&self) -> bool { - self.intersects(TC::OwnsDtor) - } -} - -impl ops::BitOr for TypeContents { - type Output = TypeContents; - - fn bitor(self, other: TypeContents) -> TypeContents { - TypeContents {bits: self.bits | other.bits} - } -} - -impl ops::BitAnd for TypeContents { - type Output = TypeContents; - - fn bitand(self, other: TypeContents) -> TypeContents { - TypeContents {bits: self.bits & other.bits} - } -} - -impl ops::Sub for TypeContents { - type Output = TypeContents; - - fn sub(self, other: TypeContents) -> TypeContents { - TypeContents {bits: self.bits & !other.bits} - } -} - -impl fmt::Debug for TypeContents { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "TypeContents({:b})", self.bits) - } -} - -impl<'tcx> ty::TyS<'tcx> { - pub fn type_contents(&'tcx self, cx: &TyCtxt<'tcx>) -> TypeContents { - return cx.tc_cache.memoize(self, || tc_ty(cx, self, &mut FnvHashMap())); - - fn tc_ty<'tcx>(cx: &TyCtxt<'tcx>, - ty: Ty<'tcx>, - cache: &mut FnvHashMap, TypeContents>) -> TypeContents - { - // Subtle: Note that we are *not* using cx.tc_cache here but rather a - // private cache for this walk. This is needed in the case of cyclic - // types like: - // - // struct List { next: Box>, ... } - // - // When computing the type contents of such a type, we wind up deeply - // recursing as we go. So when we encounter the recursive reference - // to List, we temporarily use TC::None as its contents. Later we'll - // patch up the cache with the correct value, once we've computed it - // (this is basically a co-inductive process, if that helps). So in - // the end we'll compute TC::OwnsOwned, in this case. - // - // The problem is, as we are doing the computation, we will also - // compute an *intermediate* contents for, e.g., Option of - // TC::None. This is ok during the computation of List itself, but if - // we stored this intermediate value into cx.tc_cache, then later - // requests for the contents of Option would also yield TC::None - // which is incorrect. This value was computed based on the crutch - // value for the type contents of list. The correct value is - // TC::OwnsOwned. This manifested as issue #4821. - match cache.get(&ty) { - Some(tc) => { return *tc; } - None => {} - } - match cx.tc_cache.borrow().get(&ty) { // Must check both caches! - Some(tc) => { return *tc; } - None => {} - } - cache.insert(ty, TC::None); - - let result = match ty.sty { - // usize and isize are ffi-unsafe - ty::TyUint(ast::UintTy::Us) | ty::TyInt(ast::IntTy::Is) => { - TC::None - } - - // Scalar and unique types are sendable, and durable - ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) | - ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | - ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar => { - TC::None - } - - ty::TyBox(typ) => { - tc_ty(cx, typ, cache).owned_pointer() - } - - ty::TyTrait(_) => { - TC::All - TC::InteriorParam - } - - ty::TyRawPtr(_) => { - TC::None - } - - ty::TyRef(_, _) => { - TC::None - } - - ty::TyArray(ty, _) => { - tc_ty(cx, ty, cache) - } - - ty::TySlice(ty) => { - tc_ty(cx, ty, cache) - } - ty::TyStr => TC::None, - - ty::TyClosure(_, ref substs) => { - TypeContents::union(&substs.upvar_tys, |ty| tc_ty(cx, &ty, cache)) - } - - ty::TyTuple(ref tys) => { - TypeContents::union(&tys[..], - |ty| tc_ty(cx, *ty, cache)) - } - - ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { - let mut res = - TypeContents::union(&def.variants, |v| { - TypeContents::union(&v.fields, |f| { - tc_ty(cx, f.ty(cx, substs), cache) - }) - }); - - if def.has_dtor() { - res = res | TC::OwnsDtor; - } - - apply_lang_items(cx, def.did, res) - } - - ty::TyProjection(..) | - ty::TyParam(_) => { - TC::All - } - - ty::TyInfer(_) | - ty::TyError => { - cx.sess.bug("asked to compute contents of error type"); - } - }; - - cache.insert(ty, result); - result - } - - fn apply_lang_items(cx: &TyCtxt, did: DefId, tc: TypeContents) - -> TypeContents { - if Some(did) == cx.lang_items.unsafe_cell_type() { - tc | TC::InteriorUnsafe - } else { - tc - } - } - } -} diff --git a/src/librustc/middle/ty/context.rs b/src/librustc/middle/ty/context.rs deleted file mode 100644 index 74714f71481..00000000000 --- a/src/librustc/middle/ty/context.rs +++ /dev/null @@ -1,1081 +0,0 @@ -// Copyright 2012-2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! type context book-keeping - -use dep_graph::{DepGraph, DepTrackingMap}; -use front::map as ast_map; -use session::Session; -use lint; -use middle; -use middle::cstore::{CrateStore, LOCAL_CRATE}; -use middle::def::DefMap; -use middle::def_id::DefId; -use middle::free_region::FreeRegionMap; -use middle::region::RegionMaps; -use middle::resolve_lifetime; -use middle::stability; -use middle::ty::subst::{self, Subst, Substs}; -use middle::traits; -use middle::ty::{self, TraitRef, Ty, TypeAndMut}; -use middle::ty::{TyS, TypeVariants}; -use middle::ty::{AdtDef, ClosureSubsts, ExistentialBounds, Region}; -use middle::ty::{FreevarMap}; -use middle::ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, TraitTy}; -use middle::ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid}; -use middle::ty::TypeVariants::*; -use middle::ty::maps; -use util::common::MemoizationMap; -use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet}; -use util::nodemap::FnvHashMap; - -use arena::TypedArena; -use std::borrow::Borrow; -use std::cell::{Cell, RefCell, Ref}; -use std::hash::{Hash, Hasher}; -use std::rc::Rc; -use syntax::ast::{self, Name, NodeId}; -use syntax::attr; -use syntax::parse::token::{self, special_idents}; - -use rustc_front::hir; - -/// Internal storage -pub struct CtxtArenas<'tcx> { - // internings - type_: TypedArena>, - substs: TypedArena>, - bare_fn: TypedArena>, - region: TypedArena, - stability: TypedArena, - - // references - trait_defs: TypedArena>, - adt_defs: TypedArena>, -} - -impl<'tcx> CtxtArenas<'tcx> { - pub fn new() -> CtxtArenas<'tcx> { - CtxtArenas { - type_: TypedArena::new(), - substs: TypedArena::new(), - bare_fn: TypedArena::new(), - region: TypedArena::new(), - stability: TypedArena::new(), - - trait_defs: TypedArena::new(), - adt_defs: TypedArena::new() - } - } -} - -pub struct CommonTypes<'tcx> { - pub bool: Ty<'tcx>, - pub char: Ty<'tcx>, - pub isize: Ty<'tcx>, - pub i8: Ty<'tcx>, - pub i16: Ty<'tcx>, - pub i32: Ty<'tcx>, - pub i64: Ty<'tcx>, - pub usize: Ty<'tcx>, - pub u8: Ty<'tcx>, - pub u16: Ty<'tcx>, - pub u32: Ty<'tcx>, - pub u64: Ty<'tcx>, - pub f32: Ty<'tcx>, - pub f64: Ty<'tcx>, - pub err: Ty<'tcx>, -} - -pub struct Tables<'tcx> { - /// Stores the types for various nodes in the AST. Note that this table - /// is not guaranteed to be populated until after typeck. See - /// typeck::check::fn_ctxt for details. - pub node_types: NodeMap>, - - /// Stores the type parameters which were substituted to obtain the type - /// of this node. This only applies to nodes that refer to entities - /// parameterized by type parameters, such as generic fns, types, or - /// other items. - pub item_substs: NodeMap>, - - pub adjustments: NodeMap>, - - pub method_map: ty::MethodMap<'tcx>, - - /// Borrows - pub upvar_capture_map: ty::UpvarCaptureMap, - - /// Records the type of each closure. The def ID is the ID of the - /// expression defining the closure. - pub closure_tys: DefIdMap>, - - /// Records the type of each closure. The def ID is the ID of the - /// expression defining the closure. - pub closure_kinds: DefIdMap, - - /// For each fn, records the "liberated" types of its arguments - /// and return type. Liberated means that all bound regions - /// (including late-bound regions) are replaced with free - /// equivalents. This table is not used in trans (since regions - /// are erased there) and hence is not serialized to metadata. - pub liberated_fn_sigs: NodeMap>, - - /// For each FRU expression, record the normalized types of the fields - /// of the struct - this is needed because it is non-trivial to - /// normalize while preserving regions. This table is used only in - /// MIR construction and hence is not serialized to metadata. - pub fru_field_types: NodeMap>> -} - -impl<'tcx> Tables<'tcx> { - pub fn empty() -> Tables<'tcx> { - Tables { - node_types: FnvHashMap(), - item_substs: NodeMap(), - adjustments: NodeMap(), - method_map: FnvHashMap(), - upvar_capture_map: FnvHashMap(), - closure_tys: DefIdMap(), - closure_kinds: DefIdMap(), - liberated_fn_sigs: NodeMap(), - fru_field_types: NodeMap() - } - } - - pub fn closure_kind(this: &RefCell, - tcx: &TyCtxt<'tcx>, - def_id: DefId) - -> ty::ClosureKind { - // If this is a local def-id, it should be inserted into the - // tables by typeck; else, it will be retreived from - // the external crate metadata. - if let Some(&kind) = this.borrow().closure_kinds.get(&def_id) { - return kind; - } - - let kind = tcx.sess.cstore.closure_kind(tcx, def_id); - this.borrow_mut().closure_kinds.insert(def_id, kind); - kind - } - - pub fn closure_type(this: &RefCell, - tcx: &TyCtxt<'tcx>, - def_id: DefId, - substs: &ClosureSubsts<'tcx>) - -> ty::ClosureTy<'tcx> - { - // If this is a local def-id, it should be inserted into the - // tables by typeck; else, it will be retreived from - // the external crate metadata. - if let Some(ty) = this.borrow().closure_tys.get(&def_id) { - return ty.subst(tcx, &substs.func_substs); - } - - let ty = tcx.sess.cstore.closure_ty(tcx, def_id); - this.borrow_mut().closure_tys.insert(def_id, ty.clone()); - ty.subst(tcx, &substs.func_substs) - } -} - -impl<'tcx> CommonTypes<'tcx> { - fn new(arena: &'tcx TypedArena>, - interner: &RefCell, Ty<'tcx>>>) - -> CommonTypes<'tcx> - { - let mk = |sty| TyCtxt::intern_ty(arena, interner, sty); - CommonTypes { - bool: mk(TyBool), - char: mk(TyChar), - err: mk(TyError), - isize: mk(TyInt(ast::IntTy::Is)), - i8: mk(TyInt(ast::IntTy::I8)), - i16: mk(TyInt(ast::IntTy::I16)), - i32: mk(TyInt(ast::IntTy::I32)), - i64: mk(TyInt(ast::IntTy::I64)), - usize: mk(TyUint(ast::UintTy::Us)), - u8: mk(TyUint(ast::UintTy::U8)), - u16: mk(TyUint(ast::UintTy::U16)), - u32: mk(TyUint(ast::UintTy::U32)), - u64: mk(TyUint(ast::UintTy::U64)), - f32: mk(TyFloat(ast::FloatTy::F32)), - f64: mk(TyFloat(ast::FloatTy::F64)), - } - } -} - -/// The data structure to keep track of all the information that typechecker -/// generates so that so that it can be reused and doesn't have to be redone -/// later on. -pub struct TyCtxt<'tcx> { - /// The arenas that types etc are allocated from. - arenas: &'tcx CtxtArenas<'tcx>, - - /// Specifically use a speedy hash algorithm for this hash map, it's used - /// quite often. - // FIXME(eddyb) use a FnvHashSet> when equivalent keys can - // queried from a HashSet. - interner: RefCell, Ty<'tcx>>>, - - // FIXME as above, use a hashset if equivalent elements can be queried. - substs_interner: RefCell, &'tcx Substs<'tcx>>>, - bare_fn_interner: RefCell, &'tcx BareFnTy<'tcx>>>, - region_interner: RefCell>, - stability_interner: RefCell>, - - pub dep_graph: DepGraph, - - /// Common types, pre-interned for your convenience. - pub types: CommonTypes<'tcx>, - - pub sess: &'tcx Session, - pub def_map: RefCell, - - pub named_region_map: resolve_lifetime::NamedRegionMap, - - pub region_maps: RegionMaps, - - // For each fn declared in the local crate, type check stores the - // free-region relationships that were deduced from its where - // clauses and parameter types. These are then read-again by - // borrowck. (They are not used during trans, and hence are not - // serialized or needed for cross-crate fns.) - free_region_maps: RefCell>, - // FIXME: jroesch make this a refcell - - pub tables: RefCell>, - - /// Maps from a trait item to the trait item "descriptor" - pub impl_or_trait_items: RefCell>>, - - /// Maps from a trait def-id to a list of the def-ids of its trait items - pub trait_item_def_ids: RefCell>>, - - /// A cache for the trait_items() routine; note that the routine - /// itself pushes the `TraitItems` dependency node. - trait_items_cache: RefCell>>, - - pub impl_trait_refs: RefCell>>, - pub trait_defs: RefCell>>, - pub adt_defs: RefCell>>, - - /// Maps from the def-id of an item (trait/struct/enum/fn) to its - /// associated predicates. - pub predicates: RefCell>>, - - /// Maps from the def-id of a trait to the list of - /// super-predicates. This is a subset of the full list of - /// predicates. We store these in a separate map because we must - /// evaluate them even during type conversion, often before the - /// full predicates are available (note that supertraits have - /// additional acyclicity requirements). - pub super_predicates: RefCell>>, - - pub map: ast_map::Map<'tcx>, - - // Records the free variables refrenced by every closure - // expression. Do not track deps for this, just recompute it from - // scratch every time. - pub freevars: RefCell, - - // Records the type of every item. - pub tcache: RefCell>>, - - // Internal cache for metadata decoding. No need to track deps on this. - pub rcache: RefCell>>, - - // Cache for the type-contents routine. FIXME -- track deps? - pub tc_cache: RefCell, ty::contents::TypeContents>>, - - // Cache for various types within a method body and so forth. - // - // FIXME this should be made local to typeck, but it is currently used by one lint - pub ast_ty_to_ty_cache: RefCell>>, - - // FIXME no dep tracking, but we should be able to remove this - pub ty_param_defs: RefCell>>, - - // FIXME dep tracking -- should be harmless enough - pub normalized_cache: RefCell, Ty<'tcx>>>, - - pub lang_items: middle::lang_items::LanguageItems, - - /// Maps from def-id of a type or region parameter to its - /// (inferred) variance. - pub item_variance_map: RefCell>>, - - /// True if the variance has been computed yet; false otherwise. - pub variance_computed: Cell, - - /// Maps a DefId of a type to a list of its inherent impls. - /// Contains implementations of methods that are inherent to a type. - /// Methods in these implementations don't need to be exported. - pub inherent_impls: RefCell>>, - - /// Maps a DefId of an impl to a list of its items. - /// Note that this contains all of the impls that we know about, - /// including ones in other crates. It's not clear that this is the best - /// way to do it. - pub impl_items: RefCell>>, - - /// Set of used unsafe nodes (functions or blocks). Unsafe nodes not - /// present in this set can be warned about. - pub used_unsafe: RefCell, - - /// Set of nodes which mark locals as mutable which end up getting used at - /// some point. Local variable definitions not in this set can be warned - /// about. - pub used_mut_nodes: RefCell, - - /// The set of external nominal types whose implementations have been read. - /// This is used for lazy resolution of methods. - pub populated_external_types: RefCell, - - /// The set of external primitive types whose implementations have been read. - /// FIXME(arielb1): why is this separate from populated_external_types? - pub populated_external_primitive_impls: RefCell, - - /// Cache used by const_eval when decoding external constants. - /// Contains `None` when the constant has been fetched but doesn't exist. - /// Constains `Some(expr_id, type)` otherwise. - /// `type` is `None` in case it's not a primitive type - pub extern_const_statics: RefCell>)>>>, - /// Cache used by const_eval when decoding extern const fns - pub extern_const_fns: RefCell>, - - pub node_lint_levels: RefCell>, - - /// The types that must be asserted to be the same size for `transmute` - /// to be valid. We gather up these restrictions in the intrinsicck pass - /// and check them in trans. - pub transmute_restrictions: RefCell>>, - - /// Maps any item's def-id to its stability index. - pub stability: RefCell>, - - /// Caches the results of trait selection. This cache is used - /// for things that do not have to do with the parameters in scope. - pub selection_cache: traits::SelectionCache<'tcx>, - - /// Caches the results of trait evaluation. This cache is used - /// for things that do not have to do with the parameters in scope. - /// Merge this with `selection_cache`? - pub evaluation_cache: traits::EvaluationCache<'tcx>, - - /// A set of predicates that have been fulfilled *somewhere*. - /// This is used to avoid duplicate work. Predicates are only - /// added to this set when they mention only "global" names - /// (i.e., no type or lifetime parameters). - pub fulfilled_predicates: RefCell>, - - /// Caches the representation hints for struct definitions. - repr_hint_cache: RefCell>>, - - /// Maps Expr NodeId's to their constant qualification. - pub const_qualif_map: RefCell>, - - /// Caches CoerceUnsized kinds for impls on custom types. - pub custom_coerce_unsized_kinds: RefCell>, - - /// Maps a cast expression to its kind. This is keyed on the - /// *from* expression of the cast, not the cast itself. - pub cast_kinds: RefCell>, - - /// Maps Fn items to a collection of fragment infos. - /// - /// The main goal is to identify data (each of which may be moved - /// or assigned) whose subparts are not moved nor assigned - /// (i.e. their state is *unfragmented*) and corresponding ast - /// nodes where the path to that data is moved or assigned. - /// - /// In the long term, unfragmented values will have their - /// destructor entirely driven by a single stack-local drop-flag, - /// and their parents, the collections of the unfragmented values - /// (or more simply, "fragmented values"), are mapped to the - /// corresponding collections of stack-local drop-flags. - /// - /// (However, in the short term that is not the case; e.g. some - /// unfragmented paths still need to be zeroed, namely when they - /// reference parent data from an outer scope that was not - /// entirely moved, and therefore that needs to be zeroed so that - /// we do not get double-drop when we hit the end of the parent - /// scope.) - /// - /// Also: currently the table solely holds keys for node-ids of - /// unfragmented values (see `FragmentInfo` enum definition), but - /// longer-term we will need to also store mappings from - /// fragmented data to the set of unfragmented pieces that - /// constitute it. - pub fragment_infos: RefCell>>, - - /// The definite name of the current crate after taking into account - /// attributes, commandline parameters, etc. - pub crate_name: token::InternedString, -} - -impl<'tcx> TyCtxt<'tcx> { - pub fn crate_name(&self, cnum: ast::CrateNum) -> token::InternedString { - if cnum == LOCAL_CRATE { - self.crate_name.clone() - } else { - self.sess.cstore.crate_name(cnum) - } - } - - pub fn crate_disambiguator(&self, cnum: ast::CrateNum) -> token::InternedString { - if cnum == LOCAL_CRATE { - self.sess.crate_disambiguator.get().as_str() - } else { - self.sess.cstore.crate_name(cnum) - } - } - - pub fn type_parameter_def(&self, - node_id: NodeId) - -> ty::TypeParameterDef<'tcx> - { - self.ty_param_defs.borrow().get(&node_id).unwrap().clone() - } - - pub fn node_types(&self) -> Ref>> { - fn projection<'a, 'tcx>(tables: &'a Tables<'tcx>) -> &'a NodeMap> { - &tables.node_types - } - - Ref::map(self.tables.borrow(), projection) - } - - pub fn node_type_insert(&self, id: NodeId, ty: Ty<'tcx>) { - self.tables.borrow_mut().node_types.insert(id, ty); - } - - pub fn intern_trait_def(&self, def: ty::TraitDef<'tcx>) - -> &'tcx ty::TraitDef<'tcx> { - let did = def.trait_ref.def_id; - let interned = self.arenas.trait_defs.alloc(def); - if let Some(prev) = self.trait_defs.borrow_mut().insert(did, interned) { - self.sess.bug(&format!("Tried to overwrite interned TraitDef: {:?}", - prev)) - } - interned - } - - pub fn alloc_trait_def(&self, def: ty::TraitDef<'tcx>) - -> &'tcx ty::TraitDef<'tcx> { - self.arenas.trait_defs.alloc(def) - } - - pub fn intern_adt_def(&self, - did: DefId, - kind: ty::AdtKind, - variants: Vec>) - -> ty::AdtDefMaster<'tcx> { - let def = ty::AdtDefData::new(self, did, kind, variants); - let interned = self.arenas.adt_defs.alloc(def); - // this will need a transmute when reverse-variance is removed - if let Some(prev) = self.adt_defs.borrow_mut().insert(did, interned) { - self.sess.bug(&format!("Tried to overwrite interned AdtDef: {:?}", - prev)) - } - interned - } - - pub fn intern_stability(&self, stab: attr::Stability) -> &'tcx attr::Stability { - if let Some(st) = self.stability_interner.borrow().get(&stab) { - return st; - } - - let interned = self.arenas.stability.alloc(stab); - if let Some(prev) = self.stability_interner - .borrow_mut() - .insert(interned, interned) { - self.sess.bug(&format!("Tried to overwrite interned Stability: {:?}", - prev)) - } - interned - } - - pub fn store_free_region_map(&self, id: NodeId, map: FreeRegionMap) { - if self.free_region_maps.borrow_mut().insert(id, map).is_some() { - self.sess.bug(&format!("Tried to overwrite interned FreeRegionMap for NodeId {:?}", - id)) - } - } - - pub fn free_region_map(&self, id: NodeId) -> FreeRegionMap { - self.free_region_maps.borrow()[&id].clone() - } - - pub fn lift>(&self, value: &T) -> Option { - value.lift_to_tcx(self) - } - - /// Create a type context and call the closure with a `&TyCtxt` reference - /// to the context. The closure enforces that the type context and any interned - /// value (types, substs, etc.) can only be used while `ty::tls` has a valid - /// reference to the context, to allow formatting values that need it. - pub fn create_and_enter(s: &'tcx Session, - arenas: &'tcx CtxtArenas<'tcx>, - def_map: RefCell, - named_region_map: resolve_lifetime::NamedRegionMap, - map: ast_map::Map<'tcx>, - freevars: FreevarMap, - region_maps: RegionMaps, - lang_items: middle::lang_items::LanguageItems, - stability: stability::Index<'tcx>, - crate_name: &str, - f: F) -> R - where F: FnOnce(&TyCtxt<'tcx>) -> R - { - let interner = RefCell::new(FnvHashMap()); - let common_types = CommonTypes::new(&arenas.type_, &interner); - let dep_graph = map.dep_graph.clone(); - let fulfilled_predicates = traits::GlobalFulfilledPredicates::new(dep_graph.clone()); - tls::enter(TyCtxt { - arenas: arenas, - interner: interner, - substs_interner: RefCell::new(FnvHashMap()), - bare_fn_interner: RefCell::new(FnvHashMap()), - region_interner: RefCell::new(FnvHashMap()), - stability_interner: RefCell::new(FnvHashMap()), - dep_graph: dep_graph.clone(), - types: common_types, - named_region_map: named_region_map, - region_maps: region_maps, - free_region_maps: RefCell::new(FnvHashMap()), - item_variance_map: RefCell::new(DepTrackingMap::new(dep_graph.clone())), - variance_computed: Cell::new(false), - sess: s, - def_map: def_map, - tables: RefCell::new(Tables::empty()), - impl_trait_refs: RefCell::new(DepTrackingMap::new(dep_graph.clone())), - trait_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())), - adt_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())), - predicates: RefCell::new(DepTrackingMap::new(dep_graph.clone())), - super_predicates: RefCell::new(DepTrackingMap::new(dep_graph.clone())), - fulfilled_predicates: RefCell::new(fulfilled_predicates), - map: map, - freevars: RefCell::new(freevars), - tcache: RefCell::new(DepTrackingMap::new(dep_graph.clone())), - rcache: RefCell::new(FnvHashMap()), - tc_cache: RefCell::new(FnvHashMap()), - ast_ty_to_ty_cache: RefCell::new(NodeMap()), - impl_or_trait_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())), - trait_item_def_ids: RefCell::new(DepTrackingMap::new(dep_graph.clone())), - trait_items_cache: RefCell::new(DepTrackingMap::new(dep_graph.clone())), - ty_param_defs: RefCell::new(NodeMap()), - normalized_cache: RefCell::new(FnvHashMap()), - lang_items: lang_items, - inherent_impls: RefCell::new(DepTrackingMap::new(dep_graph.clone())), - impl_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())), - used_unsafe: RefCell::new(NodeSet()), - used_mut_nodes: RefCell::new(NodeSet()), - populated_external_types: RefCell::new(DefIdSet()), - populated_external_primitive_impls: RefCell::new(DefIdSet()), - extern_const_statics: RefCell::new(DefIdMap()), - extern_const_fns: RefCell::new(DefIdMap()), - node_lint_levels: RefCell::new(FnvHashMap()), - transmute_restrictions: RefCell::new(Vec::new()), - stability: RefCell::new(stability), - selection_cache: traits::SelectionCache::new(), - evaluation_cache: traits::EvaluationCache::new(), - repr_hint_cache: RefCell::new(DepTrackingMap::new(dep_graph.clone())), - const_qualif_map: RefCell::new(NodeMap()), - custom_coerce_unsized_kinds: RefCell::new(DefIdMap()), - cast_kinds: RefCell::new(NodeMap()), - fragment_infos: RefCell::new(DefIdMap()), - crate_name: token::intern_and_get_ident(crate_name), - }, f) - } -} - -/// A trait implemented for all X<'a> types which can be safely and -/// efficiently converted to X<'tcx> as long as they are part of the -/// provided TyCtxt<'tcx>. -/// This can be done, for example, for Ty<'tcx> or &'tcx Substs<'tcx> -/// by looking them up in their respective interners. -/// None is returned if the value or one of the components is not part -/// of the provided context. -/// For Ty, None can be returned if either the type interner doesn't -/// contain the TypeVariants key or if the address of the interned -/// pointer differs. The latter case is possible if a primitive type, -/// e.g. `()` or `u8`, was interned in a different context. -pub trait Lift<'tcx> { - type Lifted; - fn lift_to_tcx(&self, tcx: &TyCtxt<'tcx>) -> Option; -} - -impl<'a, 'tcx> Lift<'tcx> for Ty<'a> { - type Lifted = Ty<'tcx>; - fn lift_to_tcx(&self, tcx: &TyCtxt<'tcx>) -> Option> { - if let Some(&ty) = tcx.interner.borrow().get(&self.sty) { - if *self as *const _ == ty as *const _ { - return Some(ty); - } - } - None - } -} - -impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> { - type Lifted = &'tcx Substs<'tcx>; - fn lift_to_tcx(&self, tcx: &TyCtxt<'tcx>) -> Option<&'tcx Substs<'tcx>> { - if let Some(&substs) = tcx.substs_interner.borrow().get(*self) { - if *self as *const _ == substs as *const _ { - return Some(substs); - } - } - None - } -} - - -pub mod tls { - use middle::ty::TyCtxt; - - use std::cell::Cell; - use std::fmt; - use syntax::codemap; - - /// Marker type used for the scoped TLS slot. - /// The type context cannot be used directly because the scoped TLS - /// in libstd doesn't allow types generic over lifetimes. - struct ThreadLocalTyCx; - - thread_local! { - static TLS_TCX: Cell> = Cell::new(None) - } - - fn span_debug(span: codemap::Span, f: &mut fmt::Formatter) -> fmt::Result { - with(|tcx| { - write!(f, "{}", tcx.sess.codemap().span_to_string(span)) - }) - } - - pub fn enter<'tcx, F: FnOnce(&TyCtxt<'tcx>) -> R, R>(tcx: TyCtxt<'tcx>, f: F) -> R { - codemap::SPAN_DEBUG.with(|span_dbg| { - let original_span_debug = span_dbg.get(); - span_dbg.set(span_debug); - let tls_ptr = &tcx as *const _ as *const ThreadLocalTyCx; - let result = TLS_TCX.with(|tls| { - let prev = tls.get(); - tls.set(Some(tls_ptr)); - let ret = f(&tcx); - tls.set(prev); - ret - }); - span_dbg.set(original_span_debug); - result - }) - } - - pub fn with R, R>(f: F) -> R { - TLS_TCX.with(|tcx| { - let tcx = tcx.get().unwrap(); - f(unsafe { &*(tcx as *const TyCtxt) }) - }) - } - - pub fn with_opt) -> R, R>(f: F) -> R { - if TLS_TCX.with(|tcx| tcx.get().is_some()) { - with(|v| f(Some(v))) - } else { - f(None) - } - } -} - -macro_rules! sty_debug_print { - ($ctxt: expr, $($variant: ident),*) => {{ - // curious inner module to allow variant names to be used as - // variable names. - #[allow(non_snake_case)] - mod inner { - use middle::ty::{self, TyCtxt}; - #[derive(Copy, Clone)] - struct DebugStat { - total: usize, - region_infer: usize, - ty_infer: usize, - both_infer: usize, - } - - pub fn go(tcx: &TyCtxt) { - let mut total = DebugStat { - total: 0, - region_infer: 0, ty_infer: 0, both_infer: 0, - }; - $(let mut $variant = total;)* - - - for (_, t) in tcx.interner.borrow().iter() { - let variant = match t.sty { - ty::TyBool | ty::TyChar | ty::TyInt(..) | ty::TyUint(..) | - ty::TyFloat(..) | ty::TyStr => continue, - ty::TyError => /* unimportant */ continue, - $(ty::$variant(..) => &mut $variant,)* - }; - let region = t.flags.get().intersects(ty::TypeFlags::HAS_RE_INFER); - let ty = t.flags.get().intersects(ty::TypeFlags::HAS_TY_INFER); - - variant.total += 1; - total.total += 1; - if region { total.region_infer += 1; variant.region_infer += 1 } - if ty { total.ty_infer += 1; variant.ty_infer += 1 } - if region && ty { total.both_infer += 1; variant.both_infer += 1 } - } - println!("Ty interner total ty region both"); - $(println!(" {:18}: {uses:6} {usespc:4.1}%, \ -{ty:4.1}% {region:5.1}% {both:4.1}%", - stringify!($variant), - uses = $variant.total, - usespc = $variant.total as f64 * 100.0 / total.total as f64, - ty = $variant.ty_infer as f64 * 100.0 / total.total as f64, - region = $variant.region_infer as f64 * 100.0 / total.total as f64, - both = $variant.both_infer as f64 * 100.0 / total.total as f64); - )* - println!(" total {uses:6} \ -{ty:4.1}% {region:5.1}% {both:4.1}%", - uses = total.total, - ty = total.ty_infer as f64 * 100.0 / total.total as f64, - region = total.region_infer as f64 * 100.0 / total.total as f64, - both = total.both_infer as f64 * 100.0 / total.total as f64) - } - } - - inner::go($ctxt) - }} -} - -impl<'tcx> TyCtxt<'tcx> { - pub fn print_debug_stats(&self) { - sty_debug_print!( - self, - TyEnum, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, - TyTrait, TyStruct, TyClosure, TyTuple, TyParam, TyInfer, TyProjection); - - println!("Substs interner: #{}", self.substs_interner.borrow().len()); - println!("BareFnTy interner: #{}", self.bare_fn_interner.borrow().len()); - println!("Region interner: #{}", self.region_interner.borrow().len()); - println!("Stability interner: #{}", self.stability_interner.borrow().len()); - } -} - - -/// An entry in the type interner. -pub struct InternedTy<'tcx> { - ty: Ty<'tcx> -} - -// NB: An InternedTy compares and hashes as a sty. -impl<'tcx> PartialEq for InternedTy<'tcx> { - fn eq(&self, other: &InternedTy<'tcx>) -> bool { - self.ty.sty == other.ty.sty - } -} - -impl<'tcx> Eq for InternedTy<'tcx> {} - -impl<'tcx> Hash for InternedTy<'tcx> { - fn hash(&self, s: &mut H) { - self.ty.sty.hash(s) - } -} - -impl<'tcx> Borrow> for InternedTy<'tcx> { - fn borrow<'a>(&'a self) -> &'a TypeVariants<'tcx> { - &self.ty.sty - } -} - -fn bound_list_is_sorted(bounds: &[ty::PolyProjectionPredicate]) -> bool { - bounds.is_empty() || - bounds[1..].iter().enumerate().all( - |(index, bound)| bounds[index].sort_key() <= bound.sort_key()) -} - -impl<'tcx> TyCtxt<'tcx> { - // Type constructors - pub fn mk_substs(&self, substs: Substs<'tcx>) -> &'tcx Substs<'tcx> { - if let Some(substs) = self.substs_interner.borrow().get(&substs) { - return *substs; - } - - let substs = self.arenas.substs.alloc(substs); - self.substs_interner.borrow_mut().insert(substs, substs); - substs - } - - /// Create an unsafe fn ty based on a safe fn ty. - pub fn safe_to_unsafe_fn_ty(&self, bare_fn: &BareFnTy<'tcx>) -> Ty<'tcx> { - assert_eq!(bare_fn.unsafety, hir::Unsafety::Normal); - self.mk_fn_ptr(ty::BareFnTy { - unsafety: hir::Unsafety::Unsafe, - abi: bare_fn.abi, - sig: bare_fn.sig.clone() - }) - } - - pub fn mk_bare_fn(&self, bare_fn: BareFnTy<'tcx>) -> &'tcx BareFnTy<'tcx> { - if let Some(bare_fn) = self.bare_fn_interner.borrow().get(&bare_fn) { - return *bare_fn; - } - - let bare_fn = self.arenas.bare_fn.alloc(bare_fn); - self.bare_fn_interner.borrow_mut().insert(bare_fn, bare_fn); - bare_fn - } - - pub fn mk_region(&self, region: Region) -> &'tcx Region { - if let Some(region) = self.region_interner.borrow().get(®ion) { - return *region; - } - - let region = self.arenas.region.alloc(region); - self.region_interner.borrow_mut().insert(region, region); - region - } - - fn intern_ty(type_arena: &'tcx TypedArena>, - interner: &RefCell, Ty<'tcx>>>, - st: TypeVariants<'tcx>) - -> Ty<'tcx> { - let ty: Ty /* don't be &mut TyS */ = { - let mut interner = interner.borrow_mut(); - match interner.get(&st) { - Some(ty) => return *ty, - _ => () - } - - let flags = super::flags::FlagComputation::for_sty(&st); - - let ty = match () { - () => type_arena.alloc(TyS { sty: st, - flags: Cell::new(flags.flags), - region_depth: flags.depth, }), - }; - - interner.insert(InternedTy { ty: ty }, ty); - ty - }; - - debug!("Interned type: {:?} Pointer: {:?}", - ty, ty as *const TyS); - ty - } - - // Interns a type/name combination, stores the resulting box in cx.interner, - // and returns the box as cast to an unsafe ptr (see comments for Ty above). - pub fn mk_ty(&self, st: TypeVariants<'tcx>) -> Ty<'tcx> { - TyCtxt::intern_ty(&self.arenas.type_, &self.interner, st) - } - - pub fn mk_mach_int(&self, tm: ast::IntTy) -> Ty<'tcx> { - match tm { - ast::IntTy::Is => self.types.isize, - ast::IntTy::I8 => self.types.i8, - ast::IntTy::I16 => self.types.i16, - ast::IntTy::I32 => self.types.i32, - ast::IntTy::I64 => self.types.i64, - } - } - - pub fn mk_mach_uint(&self, tm: ast::UintTy) -> Ty<'tcx> { - match tm { - ast::UintTy::Us => self.types.usize, - ast::UintTy::U8 => self.types.u8, - ast::UintTy::U16 => self.types.u16, - ast::UintTy::U32 => self.types.u32, - ast::UintTy::U64 => self.types.u64, - } - } - - pub fn mk_mach_float(&self, tm: ast::FloatTy) -> Ty<'tcx> { - match tm { - ast::FloatTy::F32 => self.types.f32, - ast::FloatTy::F64 => self.types.f64, - } - } - - pub fn mk_str(&self) -> Ty<'tcx> { - self.mk_ty(TyStr) - } - - pub fn mk_static_str(&self) -> Ty<'tcx> { - self.mk_imm_ref(self.mk_region(ty::ReStatic), self.mk_str()) - } - - pub fn mk_enum(&self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { - // take a copy of substs so that we own the vectors inside - self.mk_ty(TyEnum(def, substs)) - } - - pub fn mk_box(&self, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ty(TyBox(ty)) - } - - pub fn mk_ptr(&self, tm: TypeAndMut<'tcx>) -> Ty<'tcx> { - self.mk_ty(TyRawPtr(tm)) - } - - pub fn mk_ref(&self, r: &'tcx Region, tm: TypeAndMut<'tcx>) -> Ty<'tcx> { - self.mk_ty(TyRef(r, tm)) - } - - pub fn mk_mut_ref(&self, r: &'tcx Region, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ref(r, TypeAndMut {ty: ty, mutbl: hir::MutMutable}) - } - - pub fn mk_imm_ref(&self, r: &'tcx Region, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ref(r, TypeAndMut {ty: ty, mutbl: hir::MutImmutable}) - } - - pub fn mk_mut_ptr(&self, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ptr(TypeAndMut {ty: ty, mutbl: hir::MutMutable}) - } - - pub fn mk_imm_ptr(&self, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ptr(TypeAndMut {ty: ty, mutbl: hir::MutImmutable}) - } - - pub fn mk_nil_ptr(&self) -> Ty<'tcx> { - self.mk_imm_ptr(self.mk_nil()) - } - - pub fn mk_array(&self, ty: Ty<'tcx>, n: usize) -> Ty<'tcx> { - self.mk_ty(TyArray(ty, n)) - } - - pub fn mk_slice(&self, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ty(TySlice(ty)) - } - - pub fn mk_tup(&self, ts: Vec>) -> Ty<'tcx> { - self.mk_ty(TyTuple(ts)) - } - - pub fn mk_nil(&self) -> Ty<'tcx> { - self.mk_tup(Vec::new()) - } - - pub fn mk_bool(&self) -> Ty<'tcx> { - self.mk_ty(TyBool) - } - - pub fn mk_fn_def(&self, def_id: DefId, - substs: &'tcx Substs<'tcx>, - fty: BareFnTy<'tcx>) -> Ty<'tcx> { - self.mk_ty(TyFnDef(def_id, substs, self.mk_bare_fn(fty))) - } - - pub fn mk_fn_ptr(&self, fty: BareFnTy<'tcx>) -> Ty<'tcx> { - self.mk_ty(TyFnPtr(self.mk_bare_fn(fty))) - } - - pub fn mk_trait(&self, - principal: ty::PolyTraitRef<'tcx>, - bounds: ExistentialBounds<'tcx>) - -> Ty<'tcx> - { - assert!(bound_list_is_sorted(&bounds.projection_bounds)); - - let inner = box TraitTy { - principal: principal, - bounds: bounds - }; - self.mk_ty(TyTrait(inner)) - } - - pub fn mk_projection(&self, - trait_ref: TraitRef<'tcx>, - item_name: Name) - -> Ty<'tcx> { - // take a copy of substs so that we own the vectors inside - let inner = ProjectionTy { trait_ref: trait_ref, item_name: item_name }; - self.mk_ty(TyProjection(inner)) - } - - pub fn mk_struct(&self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { - // take a copy of substs so that we own the vectors inside - self.mk_ty(TyStruct(def, substs)) - } - - pub fn mk_closure(&self, - closure_id: DefId, - substs: &'tcx Substs<'tcx>, - tys: Vec>) - -> Ty<'tcx> { - self.mk_closure_from_closure_substs(closure_id, Box::new(ClosureSubsts { - func_substs: substs, - upvar_tys: tys - })) - } - - pub fn mk_closure_from_closure_substs(&self, - closure_id: DefId, - closure_substs: Box>) - -> Ty<'tcx> { - self.mk_ty(TyClosure(closure_id, closure_substs)) - } - - pub fn mk_var(&self, v: TyVid) -> Ty<'tcx> { - self.mk_infer(TyVar(v)) - } - - pub fn mk_int_var(&self, v: IntVid) -> Ty<'tcx> { - self.mk_infer(IntVar(v)) - } - - pub fn mk_float_var(&self, v: FloatVid) -> Ty<'tcx> { - self.mk_infer(FloatVar(v)) - } - - pub fn mk_infer(&self, it: InferTy) -> Ty<'tcx> { - self.mk_ty(TyInfer(it)) - } - - pub fn mk_param(&self, - space: subst::ParamSpace, - index: u32, - name: Name) -> Ty<'tcx> { - self.mk_ty(TyParam(ParamTy { space: space, idx: index, name: name })) - } - - pub fn mk_self_type(&self) -> Ty<'tcx> { - self.mk_param(subst::SelfSpace, 0, special_idents::type_self.name) - } - - pub fn mk_param_from_def(&self, def: &ty::TypeParameterDef) -> Ty<'tcx> { - self.mk_param(def.space, def.index, def.name) - } - - pub fn trait_items(&self, trait_did: DefId) -> Rc>> { - self.trait_items_cache.memoize(trait_did, || { - let def_ids = self.trait_item_def_ids(trait_did); - Rc::new(def_ids.iter() - .map(|d| self.impl_or_trait_item(d.def_id())) - .collect()) - }) - } - - /// Obtain the representation annotation for a struct definition. - pub fn lookup_repr_hints(&self, did: DefId) -> Rc> { - self.repr_hint_cache.memoize(did, || { - Rc::new(if did.is_local() { - self.get_attrs(did).iter().flat_map(|meta| { - attr::find_repr_attrs(self.sess.diagnostic(), meta).into_iter() - }).collect() - } else { - self.sess.cstore.repr_attrs(did) - }) - }) - } -} diff --git a/src/librustc/middle/ty/error.rs b/src/librustc/middle/ty/error.rs deleted file mode 100644 index 8e1ace57e42..00000000000 --- a/src/librustc/middle/ty/error.rs +++ /dev/null @@ -1,343 +0,0 @@ -// Copyright 2012-2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use middle::def_id::DefId; -use middle::ty::subst; -use middle::infer::type_variable; -use middle::ty::{self, BoundRegion, Region, Ty, TyCtxt}; - -use std::fmt; -use syntax::abi; -use syntax::ast::{self, Name}; -use syntax::codemap::Span; -use syntax::errors::DiagnosticBuilder; - -use rustc_front::hir; - -#[derive(Clone, Copy, Debug)] -pub struct ExpectedFound { - pub expected: T, - pub found: T -} - -// Data structures used in type unification -#[derive(Clone, Debug)] -pub enum TypeError<'tcx> { - Mismatch, - UnsafetyMismatch(ExpectedFound), - AbiMismatch(ExpectedFound), - Mutability, - BoxMutability, - PtrMutability, - RefMutability, - VecMutability, - TupleSize(ExpectedFound), - FixedArraySize(ExpectedFound), - TyParamSize(ExpectedFound), - ArgCount, - RegionsDoesNotOutlive(Region, Region), - RegionsNotSame(Region, Region), - RegionsNoOverlap(Region, Region), - RegionsInsufficientlyPolymorphic(BoundRegion, Region), - RegionsOverlyPolymorphic(BoundRegion, Region), - Sorts(ExpectedFound>), - IntegerAsChar, - IntMismatch(ExpectedFound), - FloatMismatch(ExpectedFound), - Traits(ExpectedFound), - BuiltinBoundsMismatch(ExpectedFound), - VariadicMismatch(ExpectedFound), - CyclicTy, - ConvergenceMismatch(ExpectedFound), - ProjectionNameMismatched(ExpectedFound), - ProjectionBoundsLength(ExpectedFound), - TyParamDefaultMismatch(ExpectedFound>) -} - -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] -pub enum UnconstrainedNumeric { - UnconstrainedFloat, - UnconstrainedInt, - Neither, -} - -/// Explains the source of a type err in a short, human readable way. This is meant to be placed -/// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()` -/// afterwards to present additional details, particularly when it comes to lifetime-related -/// errors. -impl<'tcx> fmt::Display for TypeError<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use self::TypeError::*; - fn report_maybe_different(f: &mut fmt::Formatter, - expected: String, found: String) -> fmt::Result { - // A naive approach to making sure that we're not reporting silly errors such as: - // (expected closure, found closure). - if expected == found { - write!(f, "expected {}, found a different {}", expected, found) - } else { - write!(f, "expected {}, found {}", expected, found) - } - } - - match *self { - CyclicTy => write!(f, "cyclic type of infinite size"), - Mismatch => write!(f, "types differ"), - UnsafetyMismatch(values) => { - write!(f, "expected {} fn, found {} fn", - values.expected, - values.found) - } - AbiMismatch(values) => { - write!(f, "expected {} fn, found {} fn", - values.expected, - values.found) - } - Mutability => write!(f, "values differ in mutability"), - BoxMutability => { - write!(f, "boxed values differ in mutability") - } - VecMutability => write!(f, "vectors differ in mutability"), - PtrMutability => write!(f, "pointers differ in mutability"), - RefMutability => write!(f, "references differ in mutability"), - TyParamSize(values) => { - write!(f, "expected a type with {} type params, \ - found one with {} type params", - values.expected, - values.found) - } - FixedArraySize(values) => { - write!(f, "expected an array with a fixed size of {} elements, \ - found one with {} elements", - values.expected, - values.found) - } - TupleSize(values) => { - write!(f, "expected a tuple with {} elements, \ - found one with {} elements", - values.expected, - values.found) - } - ArgCount => { - write!(f, "incorrect number of function parameters") - } - RegionsDoesNotOutlive(..) => { - write!(f, "lifetime mismatch") - } - RegionsNotSame(..) => { - write!(f, "lifetimes are not the same") - } - RegionsNoOverlap(..) => { - write!(f, "lifetimes do not intersect") - } - RegionsInsufficientlyPolymorphic(br, _) => { - write!(f, "expected bound lifetime parameter {}, \ - found concrete lifetime", br) - } - RegionsOverlyPolymorphic(br, _) => { - write!(f, "expected concrete lifetime, \ - found bound lifetime parameter {}", br) - } - Sorts(values) => ty::tls::with(|tcx| { - report_maybe_different(f, values.expected.sort_string(tcx), - values.found.sort_string(tcx)) - }), - Traits(values) => ty::tls::with(|tcx| { - report_maybe_different(f, - format!("trait `{}`", - tcx.item_path_str(values.expected)), - format!("trait `{}`", - tcx.item_path_str(values.found))) - }), - BuiltinBoundsMismatch(values) => { - if values.expected.is_empty() { - write!(f, "expected no bounds, found `{}`", - values.found) - } else if values.found.is_empty() { - write!(f, "expected bounds `{}`, found no bounds", - values.expected) - } else { - write!(f, "expected bounds `{}`, found bounds `{}`", - values.expected, - values.found) - } - } - IntegerAsChar => { - write!(f, "expected an integral type, found `char`") - } - IntMismatch(ref values) => { - write!(f, "expected `{:?}`, found `{:?}`", - values.expected, - values.found) - } - FloatMismatch(ref values) => { - write!(f, "expected `{:?}`, found `{:?}`", - values.expected, - values.found) - } - VariadicMismatch(ref values) => { - write!(f, "expected {} fn, found {} function", - if values.expected { "variadic" } else { "non-variadic" }, - if values.found { "variadic" } else { "non-variadic" }) - } - ConvergenceMismatch(ref values) => { - write!(f, "expected {} fn, found {} function", - if values.expected { "converging" } else { "diverging" }, - if values.found { "converging" } else { "diverging" }) - } - ProjectionNameMismatched(ref values) => { - write!(f, "expected {}, found {}", - values.expected, - values.found) - } - ProjectionBoundsLength(ref values) => { - write!(f, "expected {} associated type bindings, found {}", - values.expected, - values.found) - }, - TyParamDefaultMismatch(ref values) => { - write!(f, "conflicting type parameter defaults `{}` and `{}`", - values.expected.ty, - values.found.ty) - } - } - } -} - -impl<'tcx> ty::TyS<'tcx> { - fn sort_string(&self, cx: &TyCtxt) -> String { - match self.sty { - ty::TyBool | ty::TyChar | ty::TyInt(_) | - ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr => self.to_string(), - ty::TyTuple(ref tys) if tys.is_empty() => self.to_string(), - - ty::TyEnum(def, _) => format!("enum `{}`", cx.item_path_str(def.did)), - ty::TyBox(_) => "box".to_string(), - ty::TyArray(_, n) => format!("array of {} elements", n), - ty::TySlice(_) => "slice".to_string(), - ty::TyRawPtr(_) => "*-ptr".to_string(), - ty::TyRef(_, _) => "&-ptr".to_string(), - ty::TyFnDef(..) => format!("fn item"), - ty::TyFnPtr(_) => "fn pointer".to_string(), - ty::TyTrait(ref inner) => { - format!("trait {}", cx.item_path_str(inner.principal_def_id())) - } - ty::TyStruct(def, _) => { - format!("struct `{}`", cx.item_path_str(def.did)) - } - ty::TyClosure(..) => "closure".to_string(), - ty::TyTuple(_) => "tuple".to_string(), - ty::TyInfer(ty::TyVar(_)) => "inferred type".to_string(), - ty::TyInfer(ty::IntVar(_)) => "integral variable".to_string(), - ty::TyInfer(ty::FloatVar(_)) => "floating-point variable".to_string(), - ty::TyInfer(ty::FreshTy(_)) => "skolemized type".to_string(), - ty::TyInfer(ty::FreshIntTy(_)) => "skolemized integral type".to_string(), - ty::TyInfer(ty::FreshFloatTy(_)) => "skolemized floating-point type".to_string(), - ty::TyProjection(_) => "associated type".to_string(), - ty::TyParam(ref p) => { - if p.space == subst::SelfSpace { - "Self".to_string() - } else { - "type parameter".to_string() - } - } - ty::TyError => "type error".to_string(), - } - } -} - -impl<'tcx> TyCtxt<'tcx> { - pub fn note_and_explain_type_err(&self, - db: &mut DiagnosticBuilder, - err: &TypeError<'tcx>, - sp: Span) { - use self::TypeError::*; - - match err.clone() { - RegionsDoesNotOutlive(subregion, superregion) => { - self.note_and_explain_region(db, "", subregion, "..."); - self.note_and_explain_region(db, "...does not necessarily outlive ", - superregion, ""); - } - RegionsNotSame(region1, region2) => { - self.note_and_explain_region(db, "", region1, "..."); - self.note_and_explain_region(db, "...is not the same lifetime as ", - region2, ""); - } - RegionsNoOverlap(region1, region2) => { - self.note_and_explain_region(db, "", region1, "..."); - self.note_and_explain_region(db, "...does not overlap ", - region2, ""); - } - RegionsInsufficientlyPolymorphic(_, conc_region) => { - self.note_and_explain_region(db, "concrete lifetime that was found is ", - conc_region, ""); - } - RegionsOverlyPolymorphic(_, ty::ReVar(_)) => { - // don't bother to print out the message below for - // inference variables, it's not very illuminating. - } - RegionsOverlyPolymorphic(_, conc_region) => { - self.note_and_explain_region(db, "expected concrete lifetime is ", - conc_region, ""); - } - Sorts(values) => { - let expected_str = values.expected.sort_string(self); - let found_str = values.found.sort_string(self); - if expected_str == found_str && expected_str == "closure" { - db.span_note(sp, - "no two closures, even if identical, have the same type"); - db.span_help(sp, - "consider boxing your closure and/or using it as a trait object"); - } - }, - TyParamDefaultMismatch(values) => { - let expected = values.expected; - let found = values.found; - db.span_note(sp, &format!("conflicting type parameter defaults `{}` and `{}`", - expected.ty, - found.ty)); - - match - self.map.as_local_node_id(expected.def_id) - .and_then(|node_id| self.map.opt_span(node_id)) - { - Some(span) => { - db.span_note(span, "a default was defined here..."); - } - None => { - db.note(&format!("a default is defined on `{}`", - self.item_path_str(expected.def_id))); - } - } - - db.span_note( - expected.origin_span, - "...that was applied to an unconstrained type variable here"); - - match - self.map.as_local_node_id(found.def_id) - .and_then(|node_id| self.map.opt_span(node_id)) - { - Some(span) => { - db.span_note(span, "a second default was defined here..."); - } - None => { - db.note(&format!("a second default is defined on `{}`", - self.item_path_str(found.def_id))); - } - } - - db.span_note(found.origin_span, - "...that also applies to the same type variable here"); - } - _ => {} - } - } -} diff --git a/src/librustc/middle/ty/fast_reject.rs b/src/librustc/middle/ty/fast_reject.rs deleted file mode 100644 index fc4db22a8a6..00000000000 --- a/src/librustc/middle/ty/fast_reject.rs +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use middle::def_id::DefId; -use middle::ty::{self, Ty, TyCtxt}; -use syntax::ast; - -use self::SimplifiedType::*; - -/// See `simplify_type -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum SimplifiedType { - BoolSimplifiedType, - CharSimplifiedType, - IntSimplifiedType(ast::IntTy), - UintSimplifiedType(ast::UintTy), - FloatSimplifiedType(ast::FloatTy), - EnumSimplifiedType(DefId), - StrSimplifiedType, - VecSimplifiedType, - PtrSimplifiedType, - TupleSimplifiedType(usize), - TraitSimplifiedType(DefId), - StructSimplifiedType(DefId), - ClosureSimplifiedType(DefId), - FunctionSimplifiedType(usize), - ParameterSimplifiedType, -} - -/// Tries to simplify a type by dropping type parameters, deref'ing away any reference types, etc. -/// The idea is to get something simple that we can use to quickly decide if two types could unify -/// during method lookup. -/// -/// If `can_simplify_params` is false, then we will fail to simplify type parameters entirely. This -/// is useful when those type parameters would be instantiated with fresh type variables, since -/// then we can't say much about whether two types would unify. Put another way, -/// `can_simplify_params` should be true if type parameters appear free in `ty` and `false` if they -/// are to be considered bound. -pub fn simplify_type(tcx: &TyCtxt, - ty: Ty, - can_simplify_params: bool) - -> Option -{ - match ty.sty { - ty::TyBool => Some(BoolSimplifiedType), - ty::TyChar => Some(CharSimplifiedType), - ty::TyInt(int_type) => Some(IntSimplifiedType(int_type)), - ty::TyUint(uint_type) => Some(UintSimplifiedType(uint_type)), - ty::TyFloat(float_type) => Some(FloatSimplifiedType(float_type)), - ty::TyEnum(def, _) => Some(EnumSimplifiedType(def.did)), - ty::TyStr => Some(StrSimplifiedType), - ty::TyArray(..) | ty::TySlice(_) => Some(VecSimplifiedType), - ty::TyRawPtr(_) => Some(PtrSimplifiedType), - ty::TyTrait(ref trait_info) => { - Some(TraitSimplifiedType(trait_info.principal_def_id())) - } - ty::TyStruct(def, _) => { - Some(StructSimplifiedType(def.did)) - } - ty::TyRef(_, mt) => { - // since we introduce auto-refs during method lookup, we - // just treat &T and T as equivalent from the point of - // view of possibly unifying - simplify_type(tcx, mt.ty, can_simplify_params) - } - ty::TyBox(_) => { - // treat like we would treat `Box` - match tcx.lang_items.require_owned_box() { - Ok(def_id) => Some(StructSimplifiedType(def_id)), - Err(msg) => tcx.sess.fatal(&msg), - } - } - ty::TyClosure(def_id, _) => { - Some(ClosureSimplifiedType(def_id)) - } - ty::TyTuple(ref tys) => { - Some(TupleSimplifiedType(tys.len())) - } - ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => { - Some(FunctionSimplifiedType(f.sig.0.inputs.len())) - } - ty::TyProjection(_) | ty::TyParam(_) => { - if can_simplify_params { - // In normalized types, projections don't unify with - // anything. when lazy normalization happens, this - // will change. It would still be nice to have a way - // to deal with known-not-to-unify-with-anything - // projections (e.g. the likes of <__S as Encoder>::Error). - Some(ParameterSimplifiedType) - } else { - None - } - } - ty::TyInfer(_) | ty::TyError => None, - } -} diff --git a/src/librustc/middle/ty/flags.rs b/src/librustc/middle/ty/flags.rs deleted file mode 100644 index 12b24261507..00000000000 --- a/src/librustc/middle/ty/flags.rs +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright 2012-2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use middle::ty::subst; -use middle::ty::{self, Ty, TypeFlags, TypeFoldable}; - -pub struct FlagComputation { - pub flags: TypeFlags, - - // maximum depth of any bound region that we have seen thus far - pub depth: u32, -} - -impl FlagComputation { - fn new() -> FlagComputation { - FlagComputation { flags: TypeFlags::empty(), depth: 0 } - } - - pub fn for_sty(st: &ty::TypeVariants) -> FlagComputation { - let mut result = FlagComputation::new(); - result.add_sty(st); - result - } - - fn add_flags(&mut self, flags: TypeFlags) { - self.flags = self.flags | (flags & TypeFlags::NOMINAL_FLAGS); - } - - fn add_depth(&mut self, depth: u32) { - if depth > self.depth { - self.depth = depth; - } - } - - /// Adds the flags/depth from a set of types that appear within the current type, but within a - /// region binder. - fn add_bound_computation(&mut self, computation: &FlagComputation) { - self.add_flags(computation.flags); - - // The types that contributed to `computation` occurred within - // a region binder, so subtract one from the region depth - // within when adding the depth to `self`. - let depth = computation.depth; - if depth > 0 { - self.add_depth(depth - 1); - } - } - - fn add_sty(&mut self, st: &ty::TypeVariants) { - match st { - &ty::TyBool | - &ty::TyChar | - &ty::TyInt(_) | - &ty::TyFloat(_) | - &ty::TyUint(_) | - &ty::TyStr => { - } - - // You might think that we could just return TyError for - // any type containing TyError as a component, and get - // rid of the TypeFlags::HAS_TY_ERR flag -- likewise for ty_bot (with - // the exception of function types that return bot). - // But doing so caused sporadic memory corruption, and - // neither I (tjc) nor nmatsakis could figure out why, - // so we're doing it this way. - &ty::TyError => { - self.add_flags(TypeFlags::HAS_TY_ERR) - } - - &ty::TyParam(ref p) => { - self.add_flags(TypeFlags::HAS_LOCAL_NAMES); - if p.space == subst::SelfSpace { - self.add_flags(TypeFlags::HAS_SELF); - } else { - self.add_flags(TypeFlags::HAS_PARAMS); - } - } - - &ty::TyClosure(_, ref substs) => { - self.add_flags(TypeFlags::HAS_TY_CLOSURE); - self.add_flags(TypeFlags::HAS_LOCAL_NAMES); - self.add_substs(&substs.func_substs); - self.add_tys(&substs.upvar_tys); - } - - &ty::TyInfer(_) => { - self.add_flags(TypeFlags::HAS_LOCAL_NAMES); // it might, right? - self.add_flags(TypeFlags::HAS_TY_INFER) - } - - &ty::TyEnum(_, substs) | &ty::TyStruct(_, substs) => { - self.add_substs(substs); - } - - &ty::TyProjection(ref data) => { - self.add_flags(TypeFlags::HAS_PROJECTION); - self.add_projection_ty(data); - } - - &ty::TyTrait(box ty::TraitTy { ref principal, ref bounds }) => { - let mut computation = FlagComputation::new(); - computation.add_substs(principal.0.substs); - for projection_bound in &bounds.projection_bounds { - let mut proj_computation = FlagComputation::new(); - proj_computation.add_projection_predicate(&projection_bound.0); - self.add_bound_computation(&proj_computation); - } - self.add_bound_computation(&computation); - - self.add_bounds(bounds); - } - - &ty::TyBox(tt) | &ty::TyArray(tt, _) | &ty::TySlice(tt) => { - self.add_ty(tt) - } - - &ty::TyRawPtr(ref m) => { - self.add_ty(m.ty); - } - - &ty::TyRef(r, ref m) => { - self.add_region(*r); - self.add_ty(m.ty); - } - - &ty::TyTuple(ref ts) => { - self.add_tys(&ts[..]); - } - - &ty::TyFnDef(_, substs, ref f) => { - self.add_substs(substs); - self.add_fn_sig(&f.sig); - } - - &ty::TyFnPtr(ref f) => { - self.add_fn_sig(&f.sig); - } - } - } - - fn add_ty(&mut self, ty: Ty) { - self.add_flags(ty.flags.get()); - self.add_depth(ty.region_depth); - } - - fn add_tys(&mut self, tys: &[Ty]) { - for &ty in tys { - self.add_ty(ty); - } - } - - fn add_fn_sig(&mut self, fn_sig: &ty::PolyFnSig) { - let mut computation = FlagComputation::new(); - - computation.add_tys(&fn_sig.0.inputs); - - if let ty::FnConverging(output) = fn_sig.0.output { - computation.add_ty(output); - } - - self.add_bound_computation(&computation); - } - - fn add_region(&mut self, r: ty::Region) { - match r { - ty::ReVar(..) | - ty::ReSkolemized(..) => { self.add_flags(TypeFlags::HAS_RE_INFER); } - ty::ReLateBound(debruijn, _) => { self.add_depth(debruijn.depth); } - ty::ReEarlyBound(..) => { self.add_flags(TypeFlags::HAS_RE_EARLY_BOUND); } - ty::ReStatic => {} - _ => { self.add_flags(TypeFlags::HAS_FREE_REGIONS); } - } - - if !r.is_global() { - self.add_flags(TypeFlags::HAS_LOCAL_NAMES); - } - } - - fn add_projection_predicate(&mut self, projection_predicate: &ty::ProjectionPredicate) { - self.add_projection_ty(&projection_predicate.projection_ty); - self.add_ty(projection_predicate.ty); - } - - fn add_projection_ty(&mut self, projection_ty: &ty::ProjectionTy) { - self.add_substs(projection_ty.trait_ref.substs); - } - - fn add_substs(&mut self, substs: &subst::Substs) { - self.add_tys(substs.types.as_slice()); - for &r in &substs.regions { - self.add_region(r); - } - } - - fn add_bounds(&mut self, bounds: &ty::ExistentialBounds) { - self.add_region(bounds.region_bound); - } -} diff --git a/src/librustc/middle/ty/fold.rs b/src/librustc/middle/ty/fold.rs deleted file mode 100644 index 2e8782a72f6..00000000000 --- a/src/librustc/middle/ty/fold.rs +++ /dev/null @@ -1,642 +0,0 @@ -// Copyright 2012-2013 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Generalized type folding mechanism. The setup is a bit convoluted -//! but allows for convenient usage. Let T be an instance of some -//! "foldable type" (one which implements `TypeFoldable`) and F be an -//! instance of a "folder" (a type which implements `TypeFolder`). Then -//! the setup is intended to be: -//! -//! T.fold_with(F) --calls--> F.fold_T(T) --calls--> T.super_fold_with(F) -//! -//! This way, when you define a new folder F, you can override -//! `fold_T()` to customize the behavior, and invoke `T.super_fold_with()` -//! to get the original behavior. Meanwhile, to actually fold -//! something, you can just write `T.fold_with(F)`, which is -//! convenient. (Note that `fold_with` will also transparently handle -//! things like a `Vec` where T is foldable and so on.) -//! -//! In this ideal setup, the only function that actually *does* -//! anything is `T.super_fold_with()`, which traverses the type `T`. -//! Moreover, `T.super_fold_with()` should only ever call `T.fold_with()`. -//! -//! In some cases, we follow a degenerate pattern where we do not have -//! a `fold_T` method. Instead, `T.fold_with` traverses the structure directly. -//! This is suboptimal because the behavior cannot be overridden, but it's -//! much less work to implement. If you ever *do* need an override that -//! doesn't exist, it's not hard to convert the degenerate pattern into the -//! proper thing. -//! -//! A `TypeFoldable` T can also be visited by a `TypeVisitor` V using similar setup: -//! T.visit_with(V) --calls--> V.visit_T(T) --calls--> T.super_visit_with(V). -//! These methods return true to indicate that the visitor has found what it is looking for -//! and does not need to visit anything else. - -use middle::region; -use middle::ty::subst; -use middle::ty::adjustment; -use middle::ty::{self, Binder, Ty, TyCtxt, TypeFlags}; - -use std::fmt; -use util::nodemap::{FnvHashMap, FnvHashSet}; - -/// The TypeFoldable trait is implemented for every type that can be folded. -/// Basically, every type that has a corresponding method in TypeFolder. -pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { - fn super_fold_with>(&self, folder: &mut F) -> Self; - fn fold_with>(&self, folder: &mut F) -> Self { - self.super_fold_with(folder) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool; - fn visit_with>(&self, visitor: &mut V) -> bool { - self.super_visit_with(visitor) - } - - fn has_regions_escaping_depth(&self, depth: u32) -> bool { - self.visit_with(&mut HasEscapingRegionsVisitor { depth: depth }) - } - fn has_escaping_regions(&self) -> bool { - self.has_regions_escaping_depth(0) - } - - fn has_type_flags(&self, flags: TypeFlags) -> bool { - self.visit_with(&mut HasTypeFlagsVisitor { flags: flags }) - } - fn has_projection_types(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_PROJECTION) - } - fn references_error(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_ERR) - } - fn has_param_types(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_PARAMS) - } - fn has_self_ty(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_SELF) - } - fn has_infer_types(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_INFER) - } - fn needs_infer(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER) - } - fn needs_subst(&self) -> bool { - self.has_type_flags(TypeFlags::NEEDS_SUBST) - } - fn has_closure_types(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_CLOSURE) - } - fn has_erasable_regions(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_RE_EARLY_BOUND | - TypeFlags::HAS_RE_INFER | - TypeFlags::HAS_FREE_REGIONS) - } - /// Indicates whether this value references only 'global' - /// types/lifetimes that are the same regardless of what fn we are - /// in. This is used for caching. Errs on the side of returning - /// false. - fn is_global(&self) -> bool { - !self.has_type_flags(TypeFlags::HAS_LOCAL_NAMES) - } -} - -/// The TypeFolder trait defines the actual *folding*. There is a -/// method defined for every foldable type. Each of these has a -/// default implementation that does an "identity" fold. Within each -/// identity fold, it should invoke `foo.fold_with(self)` to fold each -/// sub-item. -pub trait TypeFolder<'tcx> : Sized { - fn tcx<'a>(&'a self) -> &'a TyCtxt<'tcx>; - - /// Invoked by the `super_*` routines when we enter a region - /// binding level (for example, when entering a function - /// signature). This is used by clients that want to track the - /// Debruijn index nesting level. - fn enter_region_binder(&mut self) { } - - /// Invoked by the `super_*` routines when we exit a region - /// binding level. This is used by clients that want to - /// track the Debruijn index nesting level. - fn exit_region_binder(&mut self) { } - - fn fold_binder(&mut self, t: &Binder) -> Binder - where T : TypeFoldable<'tcx> - { - // FIXME(#20526) this should replace `enter_region_binder`/`exit_region_binder`. - t.super_fold_with(self) - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - t.super_fold_with(self) - } - - fn fold_mt(&mut self, t: &ty::TypeAndMut<'tcx>) -> ty::TypeAndMut<'tcx> { - t.super_fold_with(self) - } - - fn fold_trait_ref(&mut self, t: &ty::TraitRef<'tcx>) -> ty::TraitRef<'tcx> { - t.super_fold_with(self) - } - - fn fold_impl_header(&mut self, imp: &ty::ImplHeader<'tcx>) -> ty::ImplHeader<'tcx> { - imp.super_fold_with(self) - } - - fn fold_substs(&mut self, - substs: &subst::Substs<'tcx>) - -> subst::Substs<'tcx> { - substs.super_fold_with(self) - } - - fn fold_fn_sig(&mut self, - sig: &ty::FnSig<'tcx>) - -> ty::FnSig<'tcx> { - sig.super_fold_with(self) - } - - fn fold_output(&mut self, - output: &ty::FnOutput<'tcx>) - -> ty::FnOutput<'tcx> { - output.super_fold_with(self) - } - - fn fold_bare_fn_ty(&mut self, - fty: &ty::BareFnTy<'tcx>) - -> ty::BareFnTy<'tcx> - { - fty.super_fold_with(self) - } - - fn fold_closure_ty(&mut self, - fty: &ty::ClosureTy<'tcx>) - -> ty::ClosureTy<'tcx> { - fty.super_fold_with(self) - } - - fn fold_region(&mut self, r: ty::Region) -> ty::Region { - r.super_fold_with(self) - } - - fn fold_existential_bounds(&mut self, s: &ty::ExistentialBounds<'tcx>) - -> ty::ExistentialBounds<'tcx> { - s.super_fold_with(self) - } - - fn fold_autoref(&mut self, ar: &adjustment::AutoRef<'tcx>) - -> adjustment::AutoRef<'tcx> { - ar.super_fold_with(self) - } -} - -pub trait TypeVisitor<'tcx> : Sized { - fn enter_region_binder(&mut self) { } - fn exit_region_binder(&mut self) { } - - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - t.super_visit_with(self) - } - - fn visit_region(&mut self, r: ty::Region) -> bool { - r.super_visit_with(self) - } -} - -/////////////////////////////////////////////////////////////////////////// -// Some sample folders - -pub struct BottomUpFolder<'a, 'tcx: 'a, F> where F: FnMut(Ty<'tcx>) -> Ty<'tcx> { - pub tcx: &'a TyCtxt<'tcx>, - pub fldop: F, -} - -impl<'a, 'tcx, F> TypeFolder<'tcx> for BottomUpFolder<'a, 'tcx, F> where - F: FnMut(Ty<'tcx>) -> Ty<'tcx>, -{ - fn tcx(&self) -> &TyCtxt<'tcx> { self.tcx } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - let t1 = ty.super_fold_with(self); - (self.fldop)(t1) - } -} - -/////////////////////////////////////////////////////////////////////////// -// Region folder - -impl<'tcx> TyCtxt<'tcx> { - /// Collects the free and escaping regions in `value` into `region_set`. Returns - /// whether any late-bound regions were skipped - pub fn collect_regions(&self, - value: &T, - region_set: &mut FnvHashSet) - -> bool - where T : TypeFoldable<'tcx> - { - let mut have_bound_regions = false; - self.fold_regions(value, &mut have_bound_regions, - |r, d| { region_set.insert(r.from_depth(d)); r }); - have_bound_regions - } - - /// Folds the escaping and free regions in `value` using `f`, and - /// sets `skipped_regions` to true if any late-bound region was found - /// and skipped. - pub fn fold_regions(&self, - value: &T, - skipped_regions: &mut bool, - mut f: F) - -> T - where F : FnMut(ty::Region, u32) -> ty::Region, - T : TypeFoldable<'tcx>, - { - value.fold_with(&mut RegionFolder::new(self, skipped_regions, &mut f)) - } -} - -/// Folds over the substructure of a type, visiting its component -/// types and all regions that occur *free* within it. -/// -/// That is, `Ty` can contain function or method types that bind -/// regions at the call site (`ReLateBound`), and occurrences of -/// regions (aka "lifetimes") that are bound within a type are not -/// visited by this folder; only regions that occur free will be -/// visited by `fld_r`. - -pub struct RegionFolder<'a, 'tcx: 'a> { - tcx: &'a TyCtxt<'tcx>, - skipped_regions: &'a mut bool, - current_depth: u32, - fld_r: &'a mut (FnMut(ty::Region, u32) -> ty::Region + 'a), -} - -impl<'a, 'tcx> RegionFolder<'a, 'tcx> { - pub fn new(tcx: &'a TyCtxt<'tcx>, - skipped_regions: &'a mut bool, - fld_r: &'a mut F) -> RegionFolder<'a, 'tcx> - where F : FnMut(ty::Region, u32) -> ty::Region - { - RegionFolder { - tcx: tcx, - skipped_regions: skipped_regions, - current_depth: 1, - fld_r: fld_r, - } - } -} - -impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> -{ - fn tcx(&self) -> &TyCtxt<'tcx> { self.tcx } - - fn enter_region_binder(&mut self) { - self.current_depth += 1; - } - - fn exit_region_binder(&mut self) { - self.current_depth -= 1; - } - - fn fold_region(&mut self, r: ty::Region) -> ty::Region { - match r { - ty::ReLateBound(debruijn, _) if debruijn.depth < self.current_depth => { - debug!("RegionFolder.fold_region({:?}) skipped bound region (current depth={})", - r, self.current_depth); - *self.skipped_regions = true; - r - } - _ => { - debug!("RegionFolder.fold_region({:?}) folding free region (current_depth={})", - r, self.current_depth); - (self.fld_r)(r, self.current_depth) - } - } - } -} - -/////////////////////////////////////////////////////////////////////////// -// Late-bound region replacer - -// Replaces the escaping regions in a type. - -struct RegionReplacer<'a, 'tcx: 'a> { - tcx: &'a TyCtxt<'tcx>, - current_depth: u32, - fld_r: &'a mut (FnMut(ty::BoundRegion) -> ty::Region + 'a), - map: FnvHashMap -} - -impl<'tcx> TyCtxt<'tcx> { - pub fn replace_late_bound_regions(&self, - value: &Binder, - mut f: F) - -> (T, FnvHashMap) - where F : FnMut(ty::BoundRegion) -> ty::Region, - T : TypeFoldable<'tcx>, - { - debug!("replace_late_bound_regions({:?})", value); - let mut replacer = RegionReplacer::new(self, &mut f); - let result = value.skip_binder().fold_with(&mut replacer); - (result, replacer.map) - } - - - /// Replace any late-bound regions bound in `value` with free variants attached to scope-id - /// `scope_id`. - pub fn liberate_late_bound_regions(&self, - all_outlive_scope: region::CodeExtent, - value: &Binder) - -> T - where T : TypeFoldable<'tcx> - { - self.replace_late_bound_regions(value, |br| { - ty::ReFree(ty::FreeRegion{scope: all_outlive_scope, bound_region: br}) - }).0 - } - - /// Flattens two binding levels into one. So `for<'a> for<'b> Foo` - /// becomes `for<'a,'b> Foo`. - pub fn flatten_late_bound_regions(&self, bound2_value: &Binder>) - -> Binder - where T: TypeFoldable<'tcx> - { - let bound0_value = bound2_value.skip_binder().skip_binder(); - let value = self.fold_regions(bound0_value, &mut false, - |region, current_depth| { - match region { - ty::ReLateBound(debruijn, br) if debruijn.depth >= current_depth => { - // should be true if no escaping regions from bound2_value - assert!(debruijn.depth - current_depth <= 1); - ty::ReLateBound(ty::DebruijnIndex::new(current_depth), br) - } - _ => { - region - } - } - }); - Binder(value) - } - - pub fn no_late_bound_regions(&self, value: &Binder) -> Option - where T : TypeFoldable<'tcx> - { - if value.0.has_escaping_regions() { - None - } else { - Some(value.0.clone()) - } - } - - /// Replace any late-bound regions bound in `value` with `'static`. Useful in trans but also - /// method lookup and a few other places where precise region relationships are not required. - pub fn erase_late_bound_regions(&self, value: &Binder) -> T - where T : TypeFoldable<'tcx> - { - self.replace_late_bound_regions(value, |_| ty::ReStatic).0 - } - - /// Rewrite any late-bound regions so that they are anonymous. Region numbers are - /// assigned starting at 1 and increasing monotonically in the order traversed - /// by the fold operation. - /// - /// The chief purpose of this function is to canonicalize regions so that two - /// `FnSig`s or `TraitRef`s which are equivalent up to region naming will become - /// structurally identical. For example, `for<'a, 'b> fn(&'a isize, &'b isize)` and - /// `for<'a, 'b> fn(&'b isize, &'a isize)` will become identical after anonymization. - pub fn anonymize_late_bound_regions(&self, sig: &Binder) -> Binder - where T : TypeFoldable<'tcx>, - { - let mut counter = 0; - Binder(self.replace_late_bound_regions(sig, |_| { - counter += 1; - ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrAnon(counter)) - }).0) - } -} - -impl<'a, 'tcx> RegionReplacer<'a, 'tcx> { - fn new(tcx: &'a TyCtxt<'tcx>, fld_r: &'a mut F) -> RegionReplacer<'a, 'tcx> - where F : FnMut(ty::BoundRegion) -> ty::Region - { - RegionReplacer { - tcx: tcx, - current_depth: 1, - fld_r: fld_r, - map: FnvHashMap() - } - } -} - -impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx> -{ - fn tcx(&self) -> &TyCtxt<'tcx> { self.tcx } - - fn enter_region_binder(&mut self) { - self.current_depth += 1; - } - - fn exit_region_binder(&mut self) { - self.current_depth -= 1; - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.has_regions_escaping_depth(self.current_depth-1) { - return t; - } - - t.super_fold_with(self) - } - - fn fold_region(&mut self, r: ty::Region) -> ty::Region { - match r { - ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => { - debug!("RegionReplacer.fold_region({:?}) folding region (current_depth={})", - r, self.current_depth); - let fld_r = &mut self.fld_r; - let region = *self.map.entry(br).or_insert_with(|| fld_r(br)); - if let ty::ReLateBound(debruijn1, br) = region { - // If the callback returns a late-bound region, - // that region should always use depth 1. Then we - // adjust it to the correct depth. - assert_eq!(debruijn1.depth, 1); - ty::ReLateBound(debruijn, br) - } else { - region - } - } - r => r - } - } -} - -/////////////////////////////////////////////////////////////////////////// -// Region eraser - -impl<'tcx> TyCtxt<'tcx> { - /// Returns an equivalent value with all free regions removed (note - /// that late-bound regions remain, because they are important for - /// subtyping, but they are anonymized and normalized as well).. - pub fn erase_regions(&self, value: &T) -> T - where T : TypeFoldable<'tcx> - { - let value1 = value.fold_with(&mut RegionEraser(self)); - debug!("erase_regions({:?}) = {:?}", - value, value1); - return value1; - - struct RegionEraser<'a, 'tcx: 'a>(&'a TyCtxt<'tcx>); - - impl<'a, 'tcx> TypeFolder<'tcx> for RegionEraser<'a, 'tcx> { - fn tcx(&self) -> &TyCtxt<'tcx> { self.0 } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match self.tcx().normalized_cache.borrow().get(&ty).cloned() { - None => {} - Some(u) => return u - } - - let t_norm = ty.super_fold_with(self); - self.tcx().normalized_cache.borrow_mut().insert(ty, t_norm); - return t_norm; - } - - fn fold_binder(&mut self, t: &ty::Binder) -> ty::Binder - where T : TypeFoldable<'tcx> - { - let u = self.tcx().anonymize_late_bound_regions(t); - u.super_fold_with(self) - } - - fn fold_region(&mut self, r: ty::Region) -> ty::Region { - // because late-bound regions affect subtyping, we can't - // erase the bound/free distinction, but we can replace - // all free regions with 'static. - // - // Note that we *CAN* replace early-bound regions -- the - // type system never "sees" those, they get substituted - // away. In trans, they will always be erased to 'static - // whenever a substitution occurs. - match r { - ty::ReLateBound(..) => r, - _ => ty::ReStatic - } - } - - fn fold_substs(&mut self, - substs: &subst::Substs<'tcx>) - -> subst::Substs<'tcx> { - subst::Substs { regions: substs.regions.fold_with(self), - types: substs.types.fold_with(self) } - } - } - } -} - -/////////////////////////////////////////////////////////////////////////// -// Region shifter -// -// Shifts the De Bruijn indices on all escaping bound regions by a -// fixed amount. Useful in substitution or when otherwise introducing -// a binding level that is not intended to capture the existing bound -// regions. See comment on `shift_regions_through_binders` method in -// `subst.rs` for more details. - -pub fn shift_region(region: ty::Region, amount: u32) -> ty::Region { - match region { - ty::ReLateBound(debruijn, br) => { - ty::ReLateBound(debruijn.shifted(amount), br) - } - _ => { - region - } - } -} - -pub fn shift_regions<'tcx, T:TypeFoldable<'tcx>>(tcx: &TyCtxt<'tcx>, - amount: u32, value: &T) -> T { - debug!("shift_regions(value={:?}, amount={})", - value, amount); - - value.fold_with(&mut RegionFolder::new(tcx, &mut false, &mut |region, _current_depth| { - shift_region(region, amount) - })) -} - -/// An "escaping region" is a bound region whose binder is not part of `t`. -/// -/// So, for example, consider a type like the following, which has two binders: -/// -/// for<'a> fn(x: for<'b> fn(&'a isize, &'b isize)) -/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ outer scope -/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ inner scope -/// -/// This type has *bound regions* (`'a`, `'b`), but it does not have escaping regions, because the -/// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner -/// fn type*, that type has an escaping region: `'a`. -/// -/// Note that what I'm calling an "escaping region" is often just called a "free region". However, -/// we already use the term "free region". It refers to the regions that we use to represent bound -/// regions on a fn definition while we are typechecking its body. -/// -/// To clarify, conceptually there is no particular difference between an "escaping" region and a -/// "free" region. However, there is a big difference in practice. Basically, when "entering" a -/// binding level, one is generally required to do some sort of processing to a bound region, such -/// as replacing it with a fresh/skolemized region, or making an entry in the environment to -/// represent the scope to which it is attached, etc. An escaping region represents a bound region -/// for which this processing has not yet been done. -struct HasEscapingRegionsVisitor { - depth: u32, -} - -impl<'tcx> TypeVisitor<'tcx> for HasEscapingRegionsVisitor { - fn enter_region_binder(&mut self) { - self.depth += 1; - } - - fn exit_region_binder(&mut self) { - self.depth -= 1; - } - - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - t.region_depth > self.depth - } - - fn visit_region(&mut self, r: ty::Region) -> bool { - r.escapes_depth(self.depth) - } -} - -struct HasTypeFlagsVisitor { - flags: ty::TypeFlags, -} - -impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { - fn visit_ty(&mut self, t: Ty) -> bool { - t.flags.get().intersects(self.flags) - } - - fn visit_region(&mut self, r: ty::Region) -> bool { - if self.flags.intersects(ty::TypeFlags::HAS_LOCAL_NAMES) { - // does this represent a region that cannot be named - // in a global way? used in fulfillment caching. - match r { - ty::ReStatic | ty::ReEmpty => {} - _ => return true, - } - } - if self.flags.intersects(ty::TypeFlags::HAS_RE_INFER) { - match r { - ty::ReVar(_) | ty::ReSkolemized(..) => { return true } - _ => {} - } - } - false - } -} diff --git a/src/librustc/middle/ty/item_path.rs b/src/librustc/middle/ty/item_path.rs deleted file mode 100644 index 147230f5bdc..00000000000 --- a/src/librustc/middle/ty/item_path.rs +++ /dev/null @@ -1,317 +0,0 @@ -// Copyright 2012-2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use front::map::DefPathData; -use middle::cstore::LOCAL_CRATE; -use middle::def_id::DefId; -use middle::ty::{self, Ty, TyCtxt}; -use syntax::ast; - -impl<'tcx> TyCtxt<'tcx> { - /// Returns a string identifying this def-id. This string is - /// suitable for user output. It is relative to the current crate - /// root. - pub fn item_path_str(&self, def_id: DefId) -> String { - let mut buffer = LocalPathBuffer::new(RootMode::Local); - self.push_item_path(&mut buffer, def_id); - buffer.into_string() - } - - /// Returns a string identifying this def-id. This string is - /// suitable for user output. It always begins with a crate identifier. - pub fn absolute_item_path_str(&self, def_id: DefId) -> String { - let mut buffer = LocalPathBuffer::new(RootMode::Absolute); - self.push_item_path(&mut buffer, def_id); - buffer.into_string() - } - - /// Returns the "path" to a particular crate. This can proceed in - /// various ways, depending on the `root_mode` of the `buffer`. - /// (See `RootMode` enum for more details.) - pub fn push_krate_path(&self, buffer: &mut T, cnum: ast::CrateNum) - where T: ItemPathBuffer - { - match *buffer.root_mode() { - RootMode::Local => { - // In local mode, when we encounter a crate other than - // LOCAL_CRATE, execution proceeds in one of two ways: - // - // 1. for a direct dependency, where user added an - // `extern crate` manually, we put the `extern - // crate` as the parent. So you wind up with - // something relative to the current crate. - // 2. for an indirect crate, where there is no extern - // crate, we just prepend the crate name. - // - // Returns `None` for the local crate. - if cnum != LOCAL_CRATE { - let opt_extern_crate = self.sess.cstore.extern_crate(cnum); - let opt_extern_crate = opt_extern_crate.and_then(|extern_crate| { - if extern_crate.direct { - Some(extern_crate.def_id) - } else { - None - } - }); - if let Some(extern_crate_def_id) = opt_extern_crate { - self.push_item_path(buffer, extern_crate_def_id); - } else { - buffer.push(&self.crate_name(cnum)); - } - } - } - RootMode::Absolute => { - // In absolute mode, just write the crate name - // unconditionally. - buffer.push(&self.crate_name(cnum)); - } - } - } - - pub fn push_item_path(&self, buffer: &mut T, def_id: DefId) - where T: ItemPathBuffer - { - let key = self.def_key(def_id); - match key.disambiguated_data.data { - DefPathData::CrateRoot => { - assert!(key.parent.is_none()); - self.push_krate_path(buffer, def_id.krate); - } - - DefPathData::InlinedRoot(ref root_path) => { - assert!(key.parent.is_none()); - self.push_item_path(buffer, root_path.def_id); - } - - DefPathData::Impl => { - self.push_impl_path(buffer, def_id); - } - - // Unclear if there is any value in distinguishing these. - // Probably eventually (and maybe we would even want - // finer-grained distinctions, e.g. between enum/struct). - data @ DefPathData::Misc | - data @ DefPathData::TypeNs(..) | - data @ DefPathData::ValueNs(..) | - data @ DefPathData::TypeParam(..) | - data @ DefPathData::LifetimeDef(..) | - data @ DefPathData::EnumVariant(..) | - data @ DefPathData::Field(..) | - data @ DefPathData::StructCtor | - data @ DefPathData::Initializer | - data @ DefPathData::MacroDef(..) | - data @ DefPathData::ClosureExpr | - data @ DefPathData::Binding(..) => { - let parent_def_id = self.parent_def_id(def_id).unwrap(); - self.push_item_path(buffer, parent_def_id); - buffer.push(&data.as_interned_str()); - } - } - } - - fn push_impl_path(&self, - buffer: &mut T, - impl_def_id: DefId) - where T: ItemPathBuffer - { - let parent_def_id = self.parent_def_id(impl_def_id).unwrap(); - - let use_types = if !impl_def_id.is_local() { - // always have full types available for extern crates - true - } else { - // for local crates, check whether type info is - // available; typeck might not have completed yet - self.impl_trait_refs.borrow().contains_key(&impl_def_id) - }; - - if !use_types { - return self.push_impl_path_fallback(buffer, impl_def_id); - } - - // Decide whether to print the parent path for the impl. - // Logically, since impls are global, it's never needed, but - // users may find it useful. Currently, we omit the parent if - // the impl is either in the same module as the self-type or - // as the trait. - let self_ty = self.lookup_item_type(impl_def_id).ty; - let in_self_mod = match self.characteristic_def_id_of_type(self_ty) { - None => false, - Some(ty_def_id) => self.parent_def_id(ty_def_id) == Some(parent_def_id), - }; - - let impl_trait_ref = self.impl_trait_ref(impl_def_id); - let in_trait_mod = match impl_trait_ref { - None => false, - Some(trait_ref) => self.parent_def_id(trait_ref.def_id) == Some(parent_def_id), - }; - - if !in_self_mod && !in_trait_mod { - // If the impl is not co-located with either self-type or - // trait-type, then fallback to a format that identifies - // the module more clearly. - self.push_item_path(buffer, parent_def_id); - if let Some(trait_ref) = impl_trait_ref { - buffer.push(&format!("", trait_ref, self_ty)); - } else { - buffer.push(&format!("", self_ty)); - } - return; - } - - // Otherwise, try to give a good form that would be valid language - // syntax. Preferably using associated item notation. - - if let Some(trait_ref) = impl_trait_ref { - // Trait impls. - buffer.push(&format!("<{} as {}>", - self_ty, - trait_ref)); - return; - } - - // Inherent impls. Try to print `Foo::bar` for an inherent - // impl on `Foo`, but fallback to `::bar` if self-type is - // anything other than a simple path. - match self_ty.sty { - ty::TyStruct(adt_def, substs) | - ty::TyEnum(adt_def, substs) => { - if substs.types.is_empty() { // ignore regions - self.push_item_path(buffer, adt_def.did); - } else { - buffer.push(&format!("<{}>", self_ty)); - } - } - - ty::TyBool | - ty::TyChar | - ty::TyInt(_) | - ty::TyUint(_) | - ty::TyFloat(_) | - ty::TyStr => { - buffer.push(&format!("{}", self_ty)); - } - - _ => { - buffer.push(&format!("<{}>", self_ty)); - } - } - } - - fn push_impl_path_fallback(&self, - buffer: &mut T, - impl_def_id: DefId) - where T: ItemPathBuffer - { - // If no type info is available, fall back to - // pretty printing some span information. This should - // only occur very early in the compiler pipeline. - let parent_def_id = self.parent_def_id(impl_def_id).unwrap(); - self.push_item_path(buffer, parent_def_id); - let node_id = self.map.as_local_node_id(impl_def_id).unwrap(); - let item = self.map.expect_item(node_id); - let span_str = self.sess.codemap().span_to_string(item.span); - buffer.push(&format!("", span_str)); - } - - /// As a heuristic, when we see an impl, if we see that the - /// 'self-type' is a type defined in the same module as the impl, - /// we can omit including the path to the impl itself. This - /// function tries to find a "characteristic def-id" for a - /// type. It's just a heuristic so it makes some questionable - /// decisions and we may want to adjust it later. - fn characteristic_def_id_of_type(&self, ty: Ty<'tcx>) -> Option { - match ty.sty { - ty::TyStruct(adt_def, _) | - ty::TyEnum(adt_def, _) => - Some(adt_def.did), - - ty::TyTrait(ref data) => - Some(data.principal_def_id()), - - ty::TyBox(subty) => - self.characteristic_def_id_of_type(subty), - - ty::TyRawPtr(mt) | - ty::TyRef(_, mt) => - self.characteristic_def_id_of_type(mt.ty), - - ty::TyTuple(ref tys) => - tys.iter() - .filter_map(|ty| self.characteristic_def_id_of_type(ty)) - .next(), - - _ => - None - } - } - - /// Returns the def-id of `def_id`'s parent in the def tree. If - /// this returns `None`, then `def_id` represents a crate root or - /// inlined root. - fn parent_def_id(&self, def_id: DefId) -> Option { - let key = self.def_key(def_id); - key.parent.map(|index| DefId { krate: def_id.krate, index: index }) - } -} - -/// Unifying Trait for different kinds of item paths we might -/// construct. The basic interface is that components get pushed: the -/// instance can also customize how we handle the root of a crate. -pub trait ItemPathBuffer { - fn root_mode(&self) -> &RootMode; - fn push(&mut self, text: &str); -} - -#[derive(Debug)] -pub enum RootMode { - /// Try to make a path relative to the local crate. In - /// particular, local paths have no prefix, and if the path comes - /// from an extern crate, start with the path to the `extern - /// crate` declaration. - Local, - - /// Always prepend the crate name to the path, forming an absolute - /// path from within a given set of crates. - Absolute, -} - -#[derive(Debug)] -struct LocalPathBuffer { - root_mode: RootMode, - str: String, -} - -impl LocalPathBuffer { - fn new(root_mode: RootMode) -> LocalPathBuffer { - LocalPathBuffer { - root_mode: root_mode, - str: String::new() - } - } - - fn into_string(self) -> String { - self.str - } - -} - -impl ItemPathBuffer for LocalPathBuffer { - fn root_mode(&self) -> &RootMode { - &self.root_mode - } - - fn push(&mut self, text: &str) { - if !self.str.is_empty() { - self.str.push_str("::"); - } - self.str.push_str(text); - } -} diff --git a/src/librustc/middle/ty/ivar.rs b/src/librustc/middle/ty/ivar.rs deleted file mode 100644 index ffc12aa5aea..00000000000 --- a/src/librustc/middle/ty/ivar.rs +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use dep_graph::DepNode; -use middle::ty::{Ty, TyS}; -use middle::ty::tls; - -use rustc_data_structures::ivar; - -use std::fmt; -use std::marker::PhantomData; -use core::nonzero::NonZero; - -/// An IVar that contains a Ty. 'lt is a (reverse-variant) upper bound -/// on the lifetime of the IVar. This is required because of variance -/// problems: the IVar needs to be variant with respect to 'tcx (so -/// it can be referred to from Ty) but can only be modified if its -/// lifetime is exactly 'tcx. -/// -/// Safety invariants: -/// (A) self.0, if fulfilled, is a valid Ty<'tcx> -/// (B) no aliases to this value with a 'tcx longer than this -/// value's 'lt exist -/// -/// Dependency tracking: each ivar does not know what node in the -/// dependency graph it is associated with, so when you get/fulfill -/// you must supply a `DepNode` id. This should always be the same id! -/// -/// NonZero is used rather than Unique because Unique isn't Copy. -pub struct TyIVar<'tcx, 'lt: 'tcx>(ivar::Ivar>>, - PhantomData)->TyS<'tcx>>); - -impl<'tcx, 'lt> TyIVar<'tcx, 'lt> { - #[inline] - pub fn new() -> Self { - // Invariant (A) satisfied because the IVar is unfulfilled - // Invariant (B) because 'lt : 'tcx - TyIVar(ivar::Ivar::new(), PhantomData) - } - - #[inline] - pub fn get(&self, dep_node: DepNode) -> Option> { - tls::with(|tcx| tcx.dep_graph.read(dep_node)); - self.untracked_get() - } - - #[inline] - fn untracked_get(&self) -> Option> { - match self.0.get() { - None => None, - // valid because of invariant (A) - Some(v) => Some(unsafe { &*(*v as *const TyS<'tcx>) }) - } - } - - #[inline] - pub fn unwrap(&self, dep_node: DepNode) -> Ty<'tcx> { - self.get(dep_node).unwrap() - } - - pub fn fulfill(&self, dep_node: DepNode, value: Ty<'lt>) { - tls::with(|tcx| tcx.dep_graph.write(dep_node)); - - // Invariant (A) is fulfilled, because by (B), every alias - // of this has a 'tcx longer than 'lt. - let value: *const TyS<'lt> = value; - // FIXME(27214): unneeded [as *const ()] - let value = value as *const () as *const TyS<'static>; - self.0.fulfill(unsafe { NonZero::new(value) }) - } -} - -impl<'tcx, 'lt> fmt::Debug for TyIVar<'tcx, 'lt> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.untracked_get() { - Some(val) => write!(f, "TyIVar({:?})", val), - None => f.write_str("TyIVar()") - } - } -} diff --git a/src/librustc/middle/ty/maps.rs b/src/librustc/middle/ty/maps.rs deleted file mode 100644 index 8d8afc199f5..00000000000 --- a/src/librustc/middle/ty/maps.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2012-2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use dep_graph::{DepNode, DepTrackingMapConfig}; -use middle::def_id::DefId; -use middle::ty; -use std::marker::PhantomData; -use std::rc::Rc; -use syntax::{attr, ast}; - -macro_rules! dep_map_ty { - ($ty_name:ident : $node_name:ident ($key:ty) -> $value:ty) => { - pub struct $ty_name<'tcx> { - data: PhantomData<&'tcx ()> - } - - impl<'tcx> DepTrackingMapConfig for $ty_name<'tcx> { - type Key = $key; - type Value = $value; - fn to_dep_node(key: &$key) -> DepNode { DepNode::$node_name(*key) } - } - } -} - -dep_map_ty! { ImplOrTraitItems: ImplOrTraitItems(DefId) -> ty::ImplOrTraitItem<'tcx> } -dep_map_ty! { Tcache: ItemSignature(DefId) -> ty::TypeScheme<'tcx> } -dep_map_ty! { Predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> } -dep_map_ty! { SuperPredicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> } -dep_map_ty! { TraitItemDefIds: TraitItemDefIds(DefId) -> Rc> } -dep_map_ty! { ImplTraitRefs: ItemSignature(DefId) -> Option> } -dep_map_ty! { TraitDefs: ItemSignature(DefId) -> &'tcx ty::TraitDef<'tcx> } -dep_map_ty! { AdtDefs: ItemSignature(DefId) -> ty::AdtDefMaster<'tcx> } -dep_map_ty! { ItemVariances: ItemSignature(DefId) -> Rc } -dep_map_ty! { InherentImpls: InherentImpls(DefId) -> Rc> } -dep_map_ty! { ImplItems: ImplItems(DefId) -> Vec } -dep_map_ty! { TraitItems: TraitItems(DefId) -> Rc>> } -dep_map_ty! { ReprHints: ReprHints(DefId) -> Rc> } -dep_map_ty! { InlinedClosures: Hir(DefId) -> ast::NodeId } diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs deleted file mode 100644 index 0eee78dcab3..00000000000 --- a/src/librustc/middle/ty/mod.rs +++ /dev/null @@ -1,2764 +0,0 @@ -// Copyright 2012-2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub use self::ImplOrTraitItemId::*; -pub use self::Variance::*; -pub use self::DtorKind::*; -pub use self::ImplOrTraitItemContainer::*; -pub use self::BorrowKind::*; -pub use self::ImplOrTraitItem::*; -pub use self::IntVarValue::*; -pub use self::LvaluePreference::*; -pub use self::fold::TypeFoldable; - -use dep_graph::{self, DepNode}; -use front::map as ast_map; -use front::map::LinkedPath; -use middle; -use middle::cstore::{self, CrateStore, LOCAL_CRATE}; -use middle::def::{self, Def, ExportMap}; -use middle::def_id::DefId; -use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; -use middle::region::{CodeExtent}; -use middle::traits; -use middle::ty; -use middle::ty::fold::TypeFolder; -use middle::ty::subst::{Subst, Substs, VecPerParamSpace}; -use middle::ty::walk::TypeWalker; -use util::common::MemoizationMap; -use util::nodemap::{NodeMap, NodeSet}; -use util::nodemap::FnvHashMap; - -use serialize::{Encodable, Encoder, Decodable, Decoder}; -use std::borrow::{Borrow, Cow}; -use std::cell::Cell; -use std::hash::{Hash, Hasher}; -use std::iter; -use std::rc::Rc; -use std::slice; -use std::vec::IntoIter; -use std::collections::{HashMap, HashSet}; -use syntax::ast::{self, CrateNum, Name, NodeId}; -use syntax::attr::{self, AttrMetaMethods}; -use syntax::codemap::{DUMMY_SP, Span}; -use syntax::parse::token::InternedString; - -use rustc_const_eval::ConstInt; - -use rustc_front::hir; -use rustc_front::hir::{ItemImpl, ItemTrait, PatKind}; -use rustc_front::intravisit::Visitor; - -pub use self::sty::{Binder, DebruijnIndex}; -pub use self::sty::{BuiltinBound, BuiltinBounds, ExistentialBounds}; -pub use self::sty::{BareFnTy, FnSig, PolyFnSig, FnOutput, PolyFnOutput}; -pub use self::sty::{ClosureTy, InferTy, ParamTy, ProjectionTy, TraitTy}; -pub use self::sty::{ClosureSubsts, TypeAndMut}; -pub use self::sty::{TraitRef, TypeVariants, PolyTraitRef}; -pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region}; -pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid, SkolemizedRegionVid}; -pub use self::sty::BoundRegion::*; -pub use self::sty::FnOutput::*; -pub use self::sty::InferTy::*; -pub use self::sty::Region::*; -pub use self::sty::TypeVariants::*; - -pub use self::sty::BuiltinBound::Send as BoundSend; -pub use self::sty::BuiltinBound::Sized as BoundSized; -pub use self::sty::BuiltinBound::Copy as BoundCopy; -pub use self::sty::BuiltinBound::Sync as BoundSync; - -pub use self::contents::TypeContents; -pub use self::context::{TyCtxt, tls}; -pub use self::context::{CtxtArenas, Lift, Tables}; - -pub use self::trait_def::{TraitDef, TraitFlags}; - -pub mod adjustment; -pub mod cast; -pub mod error; -pub mod fast_reject; -pub mod fold; -pub mod item_path; -pub mod _match; -pub mod maps; -pub mod outlives; -pub mod relate; -pub mod subst; -pub mod trait_def; -pub mod walk; -pub mod wf; -pub mod util; - -mod contents; -mod context; -mod flags; -mod ivar; -mod structural_impls; -mod sty; - -pub type Disr = ConstInt; - -// Data types - -/// The complete set of all analyses described in this module. This is -/// produced by the driver and fed to trans and later passes. -pub struct CrateAnalysis<'a> { - pub export_map: ExportMap, - pub access_levels: middle::privacy::AccessLevels, - pub reachable: NodeSet, - pub name: &'a str, - pub glob_map: Option, -} - -#[derive(Copy, Clone)] -pub enum DtorKind { - NoDtor, - TraitDtor(bool) -} - -impl DtorKind { - pub fn is_present(&self) -> bool { - match *self { - TraitDtor(..) => true, - _ => false - } - } - - pub fn has_drop_flag(&self) -> bool { - match self { - &NoDtor => false, - &TraitDtor(flag) => flag - } - } -} - -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub enum ImplOrTraitItemContainer { - TraitContainer(DefId), - ImplContainer(DefId), -} - -impl ImplOrTraitItemContainer { - pub fn id(&self) -> DefId { - match *self { - TraitContainer(id) => id, - ImplContainer(id) => id, - } - } -} - -/// The "header" of an impl is everything outside the body: a Self type, a trait -/// ref (in the case of a trait impl), and a set of predicates (from the -/// bounds/where clauses). -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub struct ImplHeader<'tcx> { - pub impl_def_id: DefId, - pub self_ty: Ty<'tcx>, - pub trait_ref: Option>, - pub predicates: Vec>, -} - -impl<'tcx> ImplHeader<'tcx> { - pub fn with_fresh_ty_vars<'a>(selcx: &mut traits::SelectionContext<'a, 'tcx>, - impl_def_id: DefId) - -> ImplHeader<'tcx> - { - let tcx = selcx.tcx(); - let impl_generics = tcx.lookup_item_type(impl_def_id).generics; - let impl_substs = selcx.infcx().fresh_substs_for_generics(DUMMY_SP, &impl_generics); - - let header = ImplHeader { - impl_def_id: impl_def_id, - self_ty: tcx.lookup_item_type(impl_def_id).ty, - trait_ref: tcx.impl_trait_ref(impl_def_id), - predicates: tcx.lookup_predicates(impl_def_id).predicates.into_vec(), - }.subst(tcx, &impl_substs); - - let traits::Normalized { value: mut header, obligations } = - traits::normalize(selcx, traits::ObligationCause::dummy(), &header); - - header.predicates.extend(obligations.into_iter().map(|o| o.predicate)); - header - } -} - -#[derive(Clone)] -pub enum ImplOrTraitItem<'tcx> { - ConstTraitItem(Rc>), - MethodTraitItem(Rc>), - TypeTraitItem(Rc>), -} - -impl<'tcx> ImplOrTraitItem<'tcx> { - fn id(&self) -> ImplOrTraitItemId { - match *self { - ConstTraitItem(ref associated_const) => { - ConstTraitItemId(associated_const.def_id) - } - MethodTraitItem(ref method) => MethodTraitItemId(method.def_id), - TypeTraitItem(ref associated_type) => { - TypeTraitItemId(associated_type.def_id) - } - } - } - - pub fn def(&self) -> Def { - match *self { - ConstTraitItem(ref associated_const) => Def::AssociatedConst(associated_const.def_id), - MethodTraitItem(ref method) => Def::Method(method.def_id), - TypeTraitItem(ref ty) => Def::AssociatedTy(ty.container.id(), ty.def_id), - } - } - - pub fn def_id(&self) -> DefId { - match *self { - ConstTraitItem(ref associated_const) => associated_const.def_id, - MethodTraitItem(ref method) => method.def_id, - TypeTraitItem(ref associated_type) => associated_type.def_id, - } - } - - pub fn name(&self) -> Name { - match *self { - ConstTraitItem(ref associated_const) => associated_const.name, - MethodTraitItem(ref method) => method.name, - TypeTraitItem(ref associated_type) => associated_type.name, - } - } - - pub fn vis(&self) -> hir::Visibility { - match *self { - ConstTraitItem(ref associated_const) => associated_const.vis, - MethodTraitItem(ref method) => method.vis, - TypeTraitItem(ref associated_type) => associated_type.vis, - } - } - - pub fn container(&self) -> ImplOrTraitItemContainer { - match *self { - ConstTraitItem(ref associated_const) => associated_const.container, - MethodTraitItem(ref method) => method.container, - TypeTraitItem(ref associated_type) => associated_type.container, - } - } - - pub fn as_opt_method(&self) -> Option>> { - match *self { - MethodTraitItem(ref m) => Some((*m).clone()), - _ => None, - } - } -} - -#[derive(Clone, Copy, Debug)] -pub enum ImplOrTraitItemId { - ConstTraitItemId(DefId), - MethodTraitItemId(DefId), - TypeTraitItemId(DefId), -} - -impl ImplOrTraitItemId { - pub fn def_id(&self) -> DefId { - match *self { - ConstTraitItemId(def_id) => def_id, - MethodTraitItemId(def_id) => def_id, - TypeTraitItemId(def_id) => def_id, - } - } -} - -#[derive(Clone, Debug)] -pub struct Method<'tcx> { - pub name: Name, - pub generics: Generics<'tcx>, - pub predicates: GenericPredicates<'tcx>, - pub fty: BareFnTy<'tcx>, - pub explicit_self: ExplicitSelfCategory, - pub vis: hir::Visibility, - pub defaultness: hir::Defaultness, - pub def_id: DefId, - pub container: ImplOrTraitItemContainer, -} - -impl<'tcx> Method<'tcx> { - pub fn new(name: Name, - generics: ty::Generics<'tcx>, - predicates: GenericPredicates<'tcx>, - fty: BareFnTy<'tcx>, - explicit_self: ExplicitSelfCategory, - vis: hir::Visibility, - defaultness: hir::Defaultness, - def_id: DefId, - container: ImplOrTraitItemContainer) - -> Method<'tcx> { - Method { - name: name, - generics: generics, - predicates: predicates, - fty: fty, - explicit_self: explicit_self, - vis: vis, - defaultness: defaultness, - def_id: def_id, - container: container, - } - } - - pub fn container_id(&self) -> DefId { - match self.container { - TraitContainer(id) => id, - ImplContainer(id) => id, - } - } -} - -impl<'tcx> PartialEq for Method<'tcx> { - #[inline] - fn eq(&self, other: &Self) -> bool { self.def_id == other.def_id } -} - -impl<'tcx> Eq for Method<'tcx> {} - -impl<'tcx> Hash for Method<'tcx> { - #[inline] - fn hash(&self, s: &mut H) { - self.def_id.hash(s) - } -} - -#[derive(Clone, Copy, Debug)] -pub struct AssociatedConst<'tcx> { - pub name: Name, - pub ty: Ty<'tcx>, - pub vis: hir::Visibility, - pub defaultness: hir::Defaultness, - pub def_id: DefId, - pub container: ImplOrTraitItemContainer, - pub has_value: bool -} - -#[derive(Clone, Copy, Debug)] -pub struct AssociatedType<'tcx> { - pub name: Name, - pub ty: Option>, - pub vis: hir::Visibility, - pub defaultness: hir::Defaultness, - pub def_id: DefId, - pub container: ImplOrTraitItemContainer, -} - -#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)] -pub struct ItemVariances { - pub types: VecPerParamSpace, - pub regions: VecPerParamSpace, -} - -#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Copy)] -pub enum Variance { - Covariant, // T <: T iff A <: B -- e.g., function return type - Invariant, // T <: T iff B == A -- e.g., type of mutable cell - Contravariant, // T <: T iff B <: A -- e.g., function param type - Bivariant, // T <: T -- e.g., unused type parameter -} - -#[derive(Clone, Copy, Debug)] -pub struct MethodCallee<'tcx> { - /// Impl method ID, for inherent methods, or trait method ID, otherwise. - pub def_id: DefId, - pub ty: Ty<'tcx>, - pub substs: &'tcx subst::Substs<'tcx> -} - -/// With method calls, we store some extra information in -/// side tables (i.e method_map). We use -/// MethodCall as a key to index into these tables instead of -/// just directly using the expression's NodeId. The reason -/// for this being that we may apply adjustments (coercions) -/// with the resulting expression also needing to use the -/// side tables. The problem with this is that we don't -/// assign a separate NodeId to this new expression -/// and so it would clash with the base expression if both -/// needed to add to the side tables. Thus to disambiguate -/// we also keep track of whether there's an adjustment in -/// our key. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -pub struct MethodCall { - pub expr_id: NodeId, - pub autoderef: u32 -} - -impl MethodCall { - pub fn expr(id: NodeId) -> MethodCall { - MethodCall { - expr_id: id, - autoderef: 0 - } - } - - pub fn autoderef(expr_id: NodeId, autoderef: u32) -> MethodCall { - MethodCall { - expr_id: expr_id, - autoderef: 1 + autoderef - } - } -} - -// maps from an expression id that corresponds to a method call to the details -// of the method to be invoked -pub type MethodMap<'tcx> = FnvHashMap>; - -// Contains information needed to resolve types and (in the future) look up -// the types of AST nodes. -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub struct CReaderCacheKey { - pub cnum: CrateNum, - pub pos: usize, -} - -/// A restriction that certain types must be the same size. The use of -/// `transmute` gives rise to these restrictions. These generally -/// cannot be checked until trans; therefore, each call to `transmute` -/// will push one or more such restriction into the -/// `transmute_restrictions` vector during `intrinsicck`. They are -/// then checked during `trans` by the fn `check_intrinsics`. -#[derive(Copy, Clone)] -pub struct TransmuteRestriction<'tcx> { - /// The span whence the restriction comes. - pub span: Span, - - /// The type being transmuted from. - pub original_from: Ty<'tcx>, - - /// The type being transmuted to. - pub original_to: Ty<'tcx>, - - /// The type being transmuted from, with all type parameters - /// substituted for an arbitrary representative. Not to be shown - /// to the end user. - pub substituted_from: Ty<'tcx>, - - /// The type being transmuted to, with all type parameters - /// substituted for an arbitrary representative. Not to be shown - /// to the end user. - pub substituted_to: Ty<'tcx>, - - /// NodeId of the transmute intrinsic. - pub id: NodeId, -} - -/// Describes the fragment-state associated with a NodeId. -/// -/// Currently only unfragmented paths have entries in the table, -/// but longer-term this enum is expected to expand to also -/// include data for fragmented paths. -#[derive(Copy, Clone, Debug)] -pub enum FragmentInfo { - Moved { var: NodeId, move_expr: NodeId }, - Assigned { var: NodeId, assign_expr: NodeId, assignee_id: NodeId }, -} - -// Flags that we track on types. These flags are propagated upwards -// through the type during type construction, so that we can quickly -// check whether the type has various kinds of types in it without -// recursing over the type itself. -bitflags! { - flags TypeFlags: u32 { - const HAS_PARAMS = 1 << 0, - const HAS_SELF = 1 << 1, - const HAS_TY_INFER = 1 << 2, - const HAS_RE_INFER = 1 << 3, - const HAS_RE_EARLY_BOUND = 1 << 4, - const HAS_FREE_REGIONS = 1 << 5, - const HAS_TY_ERR = 1 << 6, - const HAS_PROJECTION = 1 << 7, - const HAS_TY_CLOSURE = 1 << 8, - - // true if there are "names" of types and regions and so forth - // that are local to a particular fn - const HAS_LOCAL_NAMES = 1 << 9, - - const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits | - TypeFlags::HAS_SELF.bits | - TypeFlags::HAS_RE_EARLY_BOUND.bits, - - // Flags representing the nominal content of a type, - // computed by FlagsComputation. If you add a new nominal - // flag, it should be added here too. - const NOMINAL_FLAGS = TypeFlags::HAS_PARAMS.bits | - TypeFlags::HAS_SELF.bits | - TypeFlags::HAS_TY_INFER.bits | - TypeFlags::HAS_RE_INFER.bits | - TypeFlags::HAS_RE_EARLY_BOUND.bits | - TypeFlags::HAS_FREE_REGIONS.bits | - TypeFlags::HAS_TY_ERR.bits | - TypeFlags::HAS_PROJECTION.bits | - TypeFlags::HAS_TY_CLOSURE.bits | - TypeFlags::HAS_LOCAL_NAMES.bits, - - // Caches for type_is_sized, type_moves_by_default - const SIZEDNESS_CACHED = 1 << 16, - const IS_SIZED = 1 << 17, - const MOVENESS_CACHED = 1 << 18, - const MOVES_BY_DEFAULT = 1 << 19, - } -} - -pub struct TyS<'tcx> { - pub sty: TypeVariants<'tcx>, - pub flags: Cell, - - // the maximal depth of any bound regions appearing in this type. - region_depth: u32, -} - -impl<'tcx> PartialEq for TyS<'tcx> { - #[inline] - fn eq(&self, other: &TyS<'tcx>) -> bool { - // (self as *const _) == (other as *const _) - (self as *const TyS<'tcx>) == (other as *const TyS<'tcx>) - } -} -impl<'tcx> Eq for TyS<'tcx> {} - -impl<'tcx> Hash for TyS<'tcx> { - fn hash(&self, s: &mut H) { - (self as *const TyS).hash(s) - } -} - -pub type Ty<'tcx> = &'tcx TyS<'tcx>; - -impl<'tcx> Encodable for Ty<'tcx> { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - cstore::tls::with_encoding_context(s, |ecx, rbml_w| { - ecx.encode_ty(rbml_w, *self); - Ok(()) - }) - } -} - -impl<'tcx> Decodable for Ty<'tcx> { - fn decode(d: &mut D) -> Result, D::Error> { - cstore::tls::with_decoding_context(d, |dcx, rbml_r| { - Ok(dcx.decode_ty(rbml_r)) - }) - } -} - - -/// Upvars do not get their own node-id. Instead, we use the pair of -/// the original var id (that is, the root variable that is referenced -/// by the upvar) and the id of the closure expression. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct UpvarId { - pub var_id: NodeId, - pub closure_expr_id: NodeId, -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable, Copy)] -pub enum BorrowKind { - /// Data must be immutable and is aliasable. - ImmBorrow, - - /// Data must be immutable but not aliasable. This kind of borrow - /// cannot currently be expressed by the user and is used only in - /// implicit closure bindings. It is needed when you the closure - /// is borrowing or mutating a mutable referent, e.g.: - /// - /// let x: &mut isize = ...; - /// let y = || *x += 5; - /// - /// If we were to try to translate this closure into a more explicit - /// form, we'd encounter an error with the code as written: - /// - /// struct Env { x: & &mut isize } - /// let x: &mut isize = ...; - /// let y = (&mut Env { &x }, fn_ptr); // Closure is pair of env and fn - /// fn fn_ptr(env: &mut Env) { **env.x += 5; } - /// - /// This is then illegal because you cannot mutate a `&mut` found - /// in an aliasable location. To solve, you'd have to translate with - /// an `&mut` borrow: - /// - /// struct Env { x: & &mut isize } - /// let x: &mut isize = ...; - /// let y = (&mut Env { &mut x }, fn_ptr); // changed from &x to &mut x - /// fn fn_ptr(env: &mut Env) { **env.x += 5; } - /// - /// Now the assignment to `**env.x` is legal, but creating a - /// mutable pointer to `x` is not because `x` is not mutable. We - /// could fix this by declaring `x` as `let mut x`. This is ok in - /// user code, if awkward, but extra weird for closures, since the - /// borrow is hidden. - /// - /// So we introduce a "unique imm" borrow -- the referent is - /// immutable, but not aliasable. This solves the problem. For - /// simplicity, we don't give users the way to express this - /// borrow, it's just used when translating closures. - UniqueImmBorrow, - - /// Data is mutable and not aliasable. - MutBorrow -} - -/// Information describing the capture of an upvar. This is computed -/// during `typeck`, specifically by `regionck`. -#[derive(PartialEq, Clone, Debug, Copy)] -pub enum UpvarCapture { - /// Upvar is captured by value. This is always true when the - /// closure is labeled `move`, but can also be true in other cases - /// depending on inference. - ByValue, - - /// Upvar is captured by reference. - ByRef(UpvarBorrow), -} - -#[derive(PartialEq, Clone, Copy)] -pub struct UpvarBorrow { - /// The kind of borrow: by-ref upvars have access to shared - /// immutable borrows, which are not part of the normal language - /// syntax. - pub kind: BorrowKind, - - /// Region of the resulting reference. - pub region: ty::Region, -} - -pub type UpvarCaptureMap = FnvHashMap; - -#[derive(Copy, Clone)] -pub struct ClosureUpvar<'tcx> { - pub def: Def, - pub span: Span, - pub ty: Ty<'tcx>, -} - -#[derive(Clone, Copy, PartialEq)] -pub enum IntVarValue { - IntType(ast::IntTy), - UintType(ast::UintTy), -} - -/// Default region to use for the bound of objects that are -/// supplied as the value for this type parameter. This is derived -/// from `T:'a` annotations appearing in the type definition. If -/// this is `None`, then the default is inherited from the -/// surrounding context. See RFC #599 for details. -#[derive(Copy, Clone)] -pub enum ObjectLifetimeDefault { - /// Require an explicit annotation. Occurs when multiple - /// `T:'a` constraints are found. - Ambiguous, - - /// Use the base default, typically 'static, but in a fn body it is a fresh variable - BaseDefault, - - /// Use the given region as the default. - Specific(Region), -} - -#[derive(Clone)] -pub struct TypeParameterDef<'tcx> { - pub name: Name, - pub def_id: DefId, - pub space: subst::ParamSpace, - pub index: u32, - pub default_def_id: DefId, // for use in error reporing about defaults - pub default: Option>, - pub object_lifetime_default: ObjectLifetimeDefault, -} - -#[derive(Clone)] -pub struct RegionParameterDef { - pub name: Name, - pub def_id: DefId, - pub space: subst::ParamSpace, - pub index: u32, - pub bounds: Vec, -} - -impl RegionParameterDef { - pub fn to_early_bound_region(&self) -> ty::Region { - ty::ReEarlyBound(ty::EarlyBoundRegion { - space: self.space, - index: self.index, - name: self.name, - }) - } - pub fn to_bound_region(&self) -> ty::BoundRegion { - ty::BoundRegion::BrNamed(self.def_id, self.name) - } -} - -/// Information about the formal type/lifetime parameters associated -/// with an item or method. Analogous to hir::Generics. -#[derive(Clone, Debug)] -pub struct Generics<'tcx> { - pub types: VecPerParamSpace>, - pub regions: VecPerParamSpace, -} - -impl<'tcx> Generics<'tcx> { - pub fn empty() -> Generics<'tcx> { - Generics { - types: VecPerParamSpace::empty(), - regions: VecPerParamSpace::empty(), - } - } - - pub fn is_empty(&self) -> bool { - self.types.is_empty() && self.regions.is_empty() - } - - pub fn has_type_params(&self, space: subst::ParamSpace) -> bool { - !self.types.is_empty_in(space) - } - - pub fn has_region_params(&self, space: subst::ParamSpace) -> bool { - !self.regions.is_empty_in(space) - } -} - -/// Bounds on generics. -#[derive(Clone)] -pub struct GenericPredicates<'tcx> { - pub predicates: VecPerParamSpace>, -} - -impl<'tcx> GenericPredicates<'tcx> { - pub fn empty() -> GenericPredicates<'tcx> { - GenericPredicates { - predicates: VecPerParamSpace::empty(), - } - } - - pub fn instantiate(&self, tcx: &TyCtxt<'tcx>, substs: &Substs<'tcx>) - -> InstantiatedPredicates<'tcx> { - InstantiatedPredicates { - predicates: self.predicates.subst(tcx, substs), - } - } - - pub fn instantiate_supertrait(&self, - tcx: &TyCtxt<'tcx>, - poly_trait_ref: &ty::PolyTraitRef<'tcx>) - -> InstantiatedPredicates<'tcx> - { - InstantiatedPredicates { - predicates: self.predicates.map(|pred| pred.subst_supertrait(tcx, poly_trait_ref)) - } - } -} - -#[derive(Clone, PartialEq, Eq, Hash)] -pub enum Predicate<'tcx> { - /// Corresponds to `where Foo : Bar`. `Foo` here would be - /// the `Self` type of the trait reference and `A`, `B`, and `C` - /// would be the parameters in the `TypeSpace`. - Trait(PolyTraitPredicate<'tcx>), - - /// where `T1 == T2`. - Equate(PolyEquatePredicate<'tcx>), - - /// where 'a : 'b - RegionOutlives(PolyRegionOutlivesPredicate), - - /// where T : 'a - TypeOutlives(PolyTypeOutlivesPredicate<'tcx>), - - /// where ::Name == X, approximately. - /// See `ProjectionPredicate` struct for details. - Projection(PolyProjectionPredicate<'tcx>), - - /// no syntax: T WF - WellFormed(Ty<'tcx>), - - /// trait must be object-safe - ObjectSafe(DefId), -} - -impl<'tcx> Predicate<'tcx> { - /// Performs a substitution suitable for going from a - /// poly-trait-ref to supertraits that must hold if that - /// poly-trait-ref holds. This is slightly different from a normal - /// substitution in terms of what happens with bound regions. See - /// lengthy comment below for details. - pub fn subst_supertrait(&self, - tcx: &TyCtxt<'tcx>, - trait_ref: &ty::PolyTraitRef<'tcx>) - -> ty::Predicate<'tcx> - { - // The interaction between HRTB and supertraits is not entirely - // obvious. Let me walk you (and myself) through an example. - // - // Let's start with an easy case. Consider two traits: - // - // trait Foo<'a> : Bar<'a,'a> { } - // trait Bar<'b,'c> { } - // - // Now, if we have a trait reference `for<'x> T : Foo<'x>`, then - // we can deduce that `for<'x> T : Bar<'x,'x>`. Basically, if we - // knew that `Foo<'x>` (for any 'x) then we also know that - // `Bar<'x,'x>` (for any 'x). This more-or-less falls out from - // normal substitution. - // - // In terms of why this is sound, the idea is that whenever there - // is an impl of `T:Foo<'a>`, it must show that `T:Bar<'a,'a>` - // holds. So if there is an impl of `T:Foo<'a>` that applies to - // all `'a`, then we must know that `T:Bar<'a,'a>` holds for all - // `'a`. - // - // Another example to be careful of is this: - // - // trait Foo1<'a> : for<'b> Bar1<'a,'b> { } - // trait Bar1<'b,'c> { } - // - // Here, if we have `for<'x> T : Foo1<'x>`, then what do we know? - // The answer is that we know `for<'x,'b> T : Bar1<'x,'b>`. The - // reason is similar to the previous example: any impl of - // `T:Foo1<'x>` must show that `for<'b> T : Bar1<'x, 'b>`. So - // basically we would want to collapse the bound lifetimes from - // the input (`trait_ref`) and the supertraits. - // - // To achieve this in practice is fairly straightforward. Let's - // consider the more complicated scenario: - // - // - We start out with `for<'x> T : Foo1<'x>`. In this case, `'x` - // has a De Bruijn index of 1. We want to produce `for<'x,'b> T : Bar1<'x,'b>`, - // where both `'x` and `'b` would have a DB index of 1. - // The substitution from the input trait-ref is therefore going to be - // `'a => 'x` (where `'x` has a DB index of 1). - // - The super-trait-ref is `for<'b> Bar1<'a,'b>`, where `'a` is an - // early-bound parameter and `'b' is a late-bound parameter with a - // DB index of 1. - // - If we replace `'a` with `'x` from the input, it too will have - // a DB index of 1, and thus we'll have `for<'x,'b> Bar1<'x,'b>` - // just as we wanted. - // - // There is only one catch. If we just apply the substitution `'a - // => 'x` to `for<'b> Bar1<'a,'b>`, the substitution code will - // adjust the DB index because we substituting into a binder (it - // tries to be so smart...) resulting in `for<'x> for<'b> - // Bar1<'x,'b>` (we have no syntax for this, so use your - // imagination). Basically the 'x will have DB index of 2 and 'b - // will have DB index of 1. Not quite what we want. So we apply - // the substitution to the *contents* of the trait reference, - // rather than the trait reference itself (put another way, the - // substitution code expects equal binding levels in the values - // from the substitution and the value being substituted into, and - // this trick achieves that). - - let substs = &trait_ref.0.substs; - match *self { - Predicate::Trait(ty::Binder(ref data)) => - Predicate::Trait(ty::Binder(data.subst(tcx, substs))), - Predicate::Equate(ty::Binder(ref data)) => - Predicate::Equate(ty::Binder(data.subst(tcx, substs))), - Predicate::RegionOutlives(ty::Binder(ref data)) => - Predicate::RegionOutlives(ty::Binder(data.subst(tcx, substs))), - Predicate::TypeOutlives(ty::Binder(ref data)) => - Predicate::TypeOutlives(ty::Binder(data.subst(tcx, substs))), - Predicate::Projection(ty::Binder(ref data)) => - Predicate::Projection(ty::Binder(data.subst(tcx, substs))), - Predicate::WellFormed(data) => - Predicate::WellFormed(data.subst(tcx, substs)), - Predicate::ObjectSafe(trait_def_id) => - Predicate::ObjectSafe(trait_def_id), - } - } -} - -#[derive(Clone, PartialEq, Eq, Hash)] -pub struct TraitPredicate<'tcx> { - pub trait_ref: TraitRef<'tcx> -} -pub type PolyTraitPredicate<'tcx> = ty::Binder>; - -impl<'tcx> TraitPredicate<'tcx> { - pub fn def_id(&self) -> DefId { - self.trait_ref.def_id - } - - /// Creates the dep-node for selecting/evaluating this trait reference. - fn dep_node(&self) -> DepNode { - DepNode::TraitSelect(self.def_id()) - } - - pub fn input_types(&self) -> &[Ty<'tcx>] { - self.trait_ref.substs.types.as_slice() - } - - pub fn self_ty(&self) -> Ty<'tcx> { - self.trait_ref.self_ty() - } -} - -impl<'tcx> PolyTraitPredicate<'tcx> { - pub fn def_id(&self) -> DefId { - // ok to skip binder since trait def-id does not care about regions - self.0.def_id() - } - - pub fn dep_node(&self) -> DepNode { - // ok to skip binder since depnode does not care about regions - self.0.dep_node() - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub struct EquatePredicate<'tcx>(pub Ty<'tcx>, pub Ty<'tcx>); // `0 == 1` -pub type PolyEquatePredicate<'tcx> = ty::Binder>; - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub struct OutlivesPredicate(pub A, pub B); // `A : B` -pub type PolyOutlivesPredicate = ty::Binder>; -pub type PolyRegionOutlivesPredicate = PolyOutlivesPredicate; -pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate, ty::Region>; - -/// This kind of predicate has no *direct* correspondent in the -/// syntax, but it roughly corresponds to the syntactic forms: -/// -/// 1. `T : TraitRef<..., Item=Type>` -/// 2. `>::Item == Type` (NYI) -/// -/// In particular, form #1 is "desugared" to the combination of a -/// normal trait predicate (`T : TraitRef<...>`) and one of these -/// predicates. Form #2 is a broader form in that it also permits -/// equality between arbitrary types. Processing an instance of Form -/// #2 eventually yields one of these `ProjectionPredicate` -/// instances to normalize the LHS. -#[derive(Clone, PartialEq, Eq, Hash)] -pub struct ProjectionPredicate<'tcx> { - pub projection_ty: ProjectionTy<'tcx>, - pub ty: Ty<'tcx>, -} - -pub type PolyProjectionPredicate<'tcx> = Binder>; - -impl<'tcx> PolyProjectionPredicate<'tcx> { - pub fn item_name(&self) -> Name { - self.0.projection_ty.item_name // safe to skip the binder to access a name - } - - pub fn sort_key(&self) -> (DefId, Name) { - self.0.projection_ty.sort_key() - } -} - -pub trait ToPolyTraitRef<'tcx> { - fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>; -} - -impl<'tcx> ToPolyTraitRef<'tcx> for TraitRef<'tcx> { - fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { - assert!(!self.has_escaping_regions()); - ty::Binder(self.clone()) - } -} - -impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> { - fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { - self.map_bound_ref(|trait_pred| trait_pred.trait_ref) - } -} - -impl<'tcx> ToPolyTraitRef<'tcx> for PolyProjectionPredicate<'tcx> { - fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { - // Note: unlike with TraitRef::to_poly_trait_ref(), - // self.0.trait_ref is permitted to have escaping regions. - // This is because here `self` has a `Binder` and so does our - // return value, so we are preserving the number of binding - // levels. - ty::Binder(self.0.projection_ty.trait_ref) - } -} - -pub trait ToPredicate<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx>; -} - -impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx> { - // we're about to add a binder, so let's check that we don't - // accidentally capture anything, or else that might be some - // weird debruijn accounting. - assert!(!self.has_escaping_regions()); - - ty::Predicate::Trait(ty::Binder(ty::TraitPredicate { - trait_ref: self.clone() - })) - } -} - -impl<'tcx> ToPredicate<'tcx> for PolyTraitRef<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx> { - ty::Predicate::Trait(self.to_poly_trait_predicate()) - } -} - -impl<'tcx> ToPredicate<'tcx> for PolyEquatePredicate<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx> { - Predicate::Equate(self.clone()) - } -} - -impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate { - fn to_predicate(&self) -> Predicate<'tcx> { - Predicate::RegionOutlives(self.clone()) - } -} - -impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx> { - Predicate::TypeOutlives(self.clone()) - } -} - -impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx> { - Predicate::Projection(self.clone()) - } -} - -impl<'tcx> Predicate<'tcx> { - /// Iterates over the types in this predicate. Note that in all - /// cases this is skipping over a binder, so late-bound regions - /// with depth 0 are bound by the predicate. - pub fn walk_tys(&self) -> IntoIter> { - let vec: Vec<_> = match *self { - ty::Predicate::Trait(ref data) => { - data.0.trait_ref.substs.types.as_slice().to_vec() - } - ty::Predicate::Equate(ty::Binder(ref data)) => { - vec![data.0, data.1] - } - ty::Predicate::TypeOutlives(ty::Binder(ref data)) => { - vec![data.0] - } - ty::Predicate::RegionOutlives(..) => { - vec![] - } - ty::Predicate::Projection(ref data) => { - let trait_inputs = data.0.projection_ty.trait_ref.substs.types.as_slice(); - trait_inputs.iter() - .cloned() - .chain(Some(data.0.ty)) - .collect() - } - ty::Predicate::WellFormed(data) => { - vec![data] - } - ty::Predicate::ObjectSafe(_trait_def_id) => { - vec![] - } - }; - - // The only reason to collect into a vector here is that I was - // too lazy to make the full (somewhat complicated) iterator - // type that would be needed here. But I wanted this fn to - // return an iterator conceptually, rather than a `Vec`, so as - // to be closer to `Ty::walk`. - vec.into_iter() - } - - pub fn to_opt_poly_trait_ref(&self) -> Option> { - match *self { - Predicate::Trait(ref t) => { - Some(t.to_poly_trait_ref()) - } - Predicate::Projection(..) | - Predicate::Equate(..) | - Predicate::RegionOutlives(..) | - Predicate::WellFormed(..) | - Predicate::ObjectSafe(..) | - Predicate::TypeOutlives(..) => { - None - } - } - } -} - -/// Represents the bounds declared on a particular set of type -/// parameters. Should eventually be generalized into a flag list of -/// where clauses. You can obtain a `InstantiatedPredicates` list from a -/// `GenericPredicates` by using the `instantiate` method. Note that this method -/// reflects an important semantic invariant of `InstantiatedPredicates`: while -/// the `GenericPredicates` are expressed in terms of the bound type -/// parameters of the impl/trait/whatever, an `InstantiatedPredicates` instance -/// represented a set of bounds for some particular instantiation, -/// meaning that the generic parameters have been substituted with -/// their values. -/// -/// Example: -/// -/// struct Foo> { ... } -/// -/// Here, the `GenericPredicates` for `Foo` would contain a list of bounds like -/// `[[], [U:Bar]]`. Now if there were some particular reference -/// like `Foo`, then the `InstantiatedPredicates` would be `[[], -/// [usize:Bar]]`. -#[derive(Clone)] -pub struct InstantiatedPredicates<'tcx> { - pub predicates: VecPerParamSpace>, -} - -impl<'tcx> InstantiatedPredicates<'tcx> { - pub fn empty() -> InstantiatedPredicates<'tcx> { - InstantiatedPredicates { predicates: VecPerParamSpace::empty() } - } - - pub fn is_empty(&self) -> bool { - self.predicates.is_empty() - } -} - -impl<'tcx> TraitRef<'tcx> { - pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>) -> TraitRef<'tcx> { - TraitRef { def_id: def_id, substs: substs } - } - - pub fn self_ty(&self) -> Ty<'tcx> { - self.substs.self_ty().unwrap() - } - - pub fn input_types(&self) -> &[Ty<'tcx>] { - // Select only the "input types" from a trait-reference. For - // now this is all the types that appear in the - // trait-reference, but it should eventually exclude - // associated types. - self.substs.types.as_slice() - } -} - -/// When type checking, we use the `ParameterEnvironment` to track -/// details about the type/lifetime parameters that are in scope. -/// It primarily stores the bounds information. -/// -/// Note: This information might seem to be redundant with the data in -/// `tcx.ty_param_defs`, but it is not. That table contains the -/// parameter definitions from an "outside" perspective, but this -/// struct will contain the bounds for a parameter as seen from inside -/// the function body. Currently the only real distinction is that -/// bound lifetime parameters are replaced with free ones, but in the -/// future I hope to refine the representation of types so as to make -/// more distinctions clearer. -#[derive(Clone)] -pub struct ParameterEnvironment<'a, 'tcx:'a> { - pub tcx: &'a TyCtxt<'tcx>, - - /// See `construct_free_substs` for details. - pub free_substs: Substs<'tcx>, - - /// Each type parameter has an implicit region bound that - /// indicates it must outlive at least the function body (the user - /// may specify stronger requirements). This field indicates the - /// region of the callee. - pub implicit_region_bound: ty::Region, - - /// Obligations that the caller must satisfy. This is basically - /// the set of bounds on the in-scope type parameters, translated - /// into Obligations, and elaborated and normalized. - pub caller_bounds: Vec>, - - /// Caches the results of trait selection. This cache is used - /// for things that have to do with the parameters in scope. - pub selection_cache: traits::SelectionCache<'tcx>, - - /// Caches the results of trait evaluation. - pub evaluation_cache: traits::EvaluationCache<'tcx>, - - /// Scope that is attached to free regions for this scope. This - /// is usually the id of the fn body, but for more abstract scopes - /// like structs we often use the node-id of the struct. - /// - /// FIXME(#3696). It would be nice to refactor so that free - /// regions don't have this implicit scope and instead introduce - /// relationships in the environment. - pub free_id_outlive: CodeExtent, -} - -impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { - pub fn with_caller_bounds(&self, - caller_bounds: Vec>) - -> ParameterEnvironment<'a,'tcx> - { - ParameterEnvironment { - tcx: self.tcx, - free_substs: self.free_substs.clone(), - implicit_region_bound: self.implicit_region_bound, - caller_bounds: caller_bounds, - selection_cache: traits::SelectionCache::new(), - evaluation_cache: traits::EvaluationCache::new(), - free_id_outlive: self.free_id_outlive, - } - } - - pub fn for_item(cx: &'a TyCtxt<'tcx>, id: NodeId) -> ParameterEnvironment<'a, 'tcx> { - match cx.map.find(id) { - Some(ast_map::NodeImplItem(ref impl_item)) => { - match impl_item.node { - hir::ImplItemKind::Type(_) => { - // associated types don't have their own entry (for some reason), - // so for now just grab environment for the impl - let impl_id = cx.map.get_parent(id); - let impl_def_id = cx.map.local_def_id(impl_id); - let scheme = cx.lookup_item_type(impl_def_id); - let predicates = cx.lookup_predicates(impl_def_id); - cx.construct_parameter_environment(impl_item.span, - &scheme.generics, - &predicates, - cx.region_maps.item_extent(id)) - } - hir::ImplItemKind::Const(_, _) => { - let def_id = cx.map.local_def_id(id); - let scheme = cx.lookup_item_type(def_id); - let predicates = cx.lookup_predicates(def_id); - cx.construct_parameter_environment(impl_item.span, - &scheme.generics, - &predicates, - cx.region_maps.item_extent(id)) - } - hir::ImplItemKind::Method(_, ref body) => { - let method_def_id = cx.map.local_def_id(id); - match cx.impl_or_trait_item(method_def_id) { - MethodTraitItem(ref method_ty) => { - let method_generics = &method_ty.generics; - let method_bounds = &method_ty.predicates; - cx.construct_parameter_environment( - impl_item.span, - method_generics, - method_bounds, - cx.region_maps.call_site_extent(id, body.id)) - } - _ => { - cx.sess - .bug("ParameterEnvironment::for_item(): \ - got non-method item from impl method?!") - } - } - } - } - } - Some(ast_map::NodeTraitItem(trait_item)) => { - match trait_item.node { - hir::TypeTraitItem(..) => { - // associated types don't have their own entry (for some reason), - // so for now just grab environment for the trait - let trait_id = cx.map.get_parent(id); - let trait_def_id = cx.map.local_def_id(trait_id); - let trait_def = cx.lookup_trait_def(trait_def_id); - let predicates = cx.lookup_predicates(trait_def_id); - cx.construct_parameter_environment(trait_item.span, - &trait_def.generics, - &predicates, - cx.region_maps.item_extent(id)) - } - hir::ConstTraitItem(..) => { - let def_id = cx.map.local_def_id(id); - let scheme = cx.lookup_item_type(def_id); - let predicates = cx.lookup_predicates(def_id); - cx.construct_parameter_environment(trait_item.span, - &scheme.generics, - &predicates, - cx.region_maps.item_extent(id)) - } - hir::MethodTraitItem(_, ref body) => { - // Use call-site for extent (unless this is a - // trait method with no default; then fallback - // to the method id). - let method_def_id = cx.map.local_def_id(id); - match cx.impl_or_trait_item(method_def_id) { - MethodTraitItem(ref method_ty) => { - let method_generics = &method_ty.generics; - let method_bounds = &method_ty.predicates; - let extent = if let Some(ref body) = *body { - // default impl: use call_site extent as free_id_outlive bound. - cx.region_maps.call_site_extent(id, body.id) - } else { - // no default impl: use item extent as free_id_outlive bound. - cx.region_maps.item_extent(id) - }; - cx.construct_parameter_environment( - trait_item.span, - method_generics, - method_bounds, - extent) - } - _ => { - cx.sess - .bug("ParameterEnvironment::for_item(): \ - got non-method item from provided \ - method?!") - } - } - } - } - } - Some(ast_map::NodeItem(item)) => { - match item.node { - hir::ItemFn(_, _, _, _, _, ref body) => { - // We assume this is a function. - let fn_def_id = cx.map.local_def_id(id); - let fn_scheme = cx.lookup_item_type(fn_def_id); - let fn_predicates = cx.lookup_predicates(fn_def_id); - - cx.construct_parameter_environment(item.span, - &fn_scheme.generics, - &fn_predicates, - cx.region_maps.call_site_extent(id, - body.id)) - } - hir::ItemEnum(..) | - hir::ItemStruct(..) | - hir::ItemImpl(..) | - hir::ItemConst(..) | - hir::ItemStatic(..) => { - let def_id = cx.map.local_def_id(id); - let scheme = cx.lookup_item_type(def_id); - let predicates = cx.lookup_predicates(def_id); - cx.construct_parameter_environment(item.span, - &scheme.generics, - &predicates, - cx.region_maps.item_extent(id)) - } - hir::ItemTrait(..) => { - let def_id = cx.map.local_def_id(id); - let trait_def = cx.lookup_trait_def(def_id); - let predicates = cx.lookup_predicates(def_id); - cx.construct_parameter_environment(item.span, - &trait_def.generics, - &predicates, - cx.region_maps.item_extent(id)) - } - _ => { - cx.sess.span_bug(item.span, - "ParameterEnvironment::from_item(): - can't create a parameter \ - environment for this kind of item") - } - } - } - Some(ast_map::NodeExpr(..)) => { - // This is a convenience to allow closures to work. - ParameterEnvironment::for_item(cx, cx.map.get_parent(id)) - } - _ => { - cx.sess.bug(&format!("ParameterEnvironment::from_item(): \ - `{}` is not an item", - cx.map.node_to_string(id))) - } - } - } -} - -/// A "type scheme", in ML terminology, is a type combined with some -/// set of generic types that the type is, well, generic over. In Rust -/// terms, it is the "type" of a fn item or struct -- this type will -/// include various generic parameters that must be substituted when -/// the item/struct is referenced. That is called converting the type -/// scheme to a monotype. -/// -/// - `generics`: the set of type parameters and their bounds -/// - `ty`: the base types, which may reference the parameters defined -/// in `generics` -/// -/// Note that TypeSchemes are also sometimes called "polytypes" (and -/// in fact this struct used to carry that name, so you may find some -/// stray references in a comment or something). We try to reserve the -/// "poly" prefix to refer to higher-ranked things, as in -/// `PolyTraitRef`. -/// -/// Note that each item also comes with predicates, see -/// `lookup_predicates`. -#[derive(Clone, Debug)] -pub struct TypeScheme<'tcx> { - pub generics: Generics<'tcx>, - pub ty: Ty<'tcx>, -} - -bitflags! { - flags AdtFlags: u32 { - const NO_ADT_FLAGS = 0, - const IS_ENUM = 1 << 0, - const IS_DTORCK = 1 << 1, // is this a dtorck type? - const IS_DTORCK_VALID = 1 << 2, - const IS_PHANTOM_DATA = 1 << 3, - const IS_SIMD = 1 << 4, - const IS_FUNDAMENTAL = 1 << 5, - const IS_NO_DROP_FLAG = 1 << 6, - } -} - -pub type AdtDef<'tcx> = &'tcx AdtDefData<'tcx, 'static>; -pub type VariantDef<'tcx> = &'tcx VariantDefData<'tcx, 'static>; -pub type FieldDef<'tcx> = &'tcx FieldDefData<'tcx, 'static>; - -// See comment on AdtDefData for explanation -pub type AdtDefMaster<'tcx> = &'tcx AdtDefData<'tcx, 'tcx>; -pub type VariantDefMaster<'tcx> = &'tcx VariantDefData<'tcx, 'tcx>; -pub type FieldDefMaster<'tcx> = &'tcx FieldDefData<'tcx, 'tcx>; - -pub struct VariantDefData<'tcx, 'container: 'tcx> { - /// The variant's DefId. If this is a tuple-like struct, - /// this is the DefId of the struct's ctor. - pub did: DefId, - pub name: Name, // struct's name if this is a struct - pub disr_val: Disr, - pub fields: Vec>, - pub kind: VariantKind, -} - -pub struct FieldDefData<'tcx, 'container: 'tcx> { - /// The field's DefId. NOTE: the fields of tuple-like enum variants - /// are not real items, and don't have entries in tcache etc. - pub did: DefId, - pub name: Name, - pub vis: hir::Visibility, - /// TyIVar is used here to allow for variance (see the doc at - /// AdtDefData). - /// - /// Note: direct accesses to `ty` must also add dep edges. - ty: ivar::TyIVar<'tcx, 'container> -} - -/// The definition of an abstract data type - a struct or enum. -/// -/// These are all interned (by intern_adt_def) into the adt_defs -/// table. -/// -/// Because of the possibility of nested tcx-s, this type -/// needs 2 lifetimes: the traditional variant lifetime ('tcx) -/// bounding the lifetime of the inner types is of course necessary. -/// However, it is not sufficient - types from a child tcx must -/// not be leaked into the master tcx by being stored in an AdtDefData. -/// -/// The 'container lifetime ensures that by outliving the container -/// tcx and preventing shorter-lived types from being inserted. When -/// write access is not needed, the 'container lifetime can be -/// erased to 'static, which can be done by the AdtDef wrapper. -pub struct AdtDefData<'tcx, 'container: 'tcx> { - pub did: DefId, - pub variants: Vec>, - destructor: Cell>, - flags: Cell, -} - -impl<'tcx, 'container> PartialEq for AdtDefData<'tcx, 'container> { - // AdtDefData are always interned and this is part of TyS equality - #[inline] - fn eq(&self, other: &Self) -> bool { self as *const _ == other as *const _ } -} - -impl<'tcx, 'container> Eq for AdtDefData<'tcx, 'container> {} - -impl<'tcx, 'container> Hash for AdtDefData<'tcx, 'container> { - #[inline] - fn hash(&self, s: &mut H) { - (self as *const AdtDefData).hash(s) - } -} - -impl<'tcx> Encodable for AdtDef<'tcx> { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - self.did.encode(s) - } -} - -impl<'tcx> Decodable for AdtDef<'tcx> { - fn decode(d: &mut D) -> Result, D::Error> { - let def_id: DefId = Decodable::decode(d)?; - - cstore::tls::with_decoding_context(d, |dcx, _| { - let def_id = dcx.translate_def_id(def_id); - Ok(dcx.tcx().lookup_adt_def(def_id)) - }) - } -} - - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum AdtKind { Struct, Enum } - -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] -pub enum VariantKind { Struct, Tuple, Unit } - -impl VariantKind { - pub fn from_variant_data(vdata: &hir::VariantData) -> Self { - match *vdata { - hir::VariantData::Struct(..) => VariantKind::Struct, - hir::VariantData::Tuple(..) => VariantKind::Tuple, - hir::VariantData::Unit(..) => VariantKind::Unit, - } - } -} - -impl<'tcx, 'container> AdtDefData<'tcx, 'container> { - fn new(tcx: &TyCtxt<'tcx>, - did: DefId, - kind: AdtKind, - variants: Vec>) -> Self { - let mut flags = AdtFlags::NO_ADT_FLAGS; - let attrs = tcx.get_attrs(did); - if attr::contains_name(&attrs, "fundamental") { - flags = flags | AdtFlags::IS_FUNDAMENTAL; - } - if attr::contains_name(&attrs, "unsafe_no_drop_flag") { - flags = flags | AdtFlags::IS_NO_DROP_FLAG; - } - if tcx.lookup_simd(did) { - flags = flags | AdtFlags::IS_SIMD; - } - if Some(did) == tcx.lang_items.phantom_data() { - flags = flags | AdtFlags::IS_PHANTOM_DATA; - } - if let AdtKind::Enum = kind { - flags = flags | AdtFlags::IS_ENUM; - } - AdtDefData { - did: did, - variants: variants, - flags: Cell::new(flags), - destructor: Cell::new(None) - } - } - - fn calculate_dtorck(&'tcx self, tcx: &TyCtxt<'tcx>) { - if tcx.is_adt_dtorck(self) { - self.flags.set(self.flags.get() | AdtFlags::IS_DTORCK); - } - self.flags.set(self.flags.get() | AdtFlags::IS_DTORCK_VALID) - } - - /// Returns the kind of the ADT - Struct or Enum. - #[inline] - pub fn adt_kind(&self) -> AdtKind { - if self.flags.get().intersects(AdtFlags::IS_ENUM) { - AdtKind::Enum - } else { - AdtKind::Struct - } - } - - /// Returns whether this is a dtorck type. If this returns - /// true, this type being safe for destruction requires it to be - /// alive; Otherwise, only the contents are required to be. - #[inline] - pub fn is_dtorck(&'tcx self, tcx: &TyCtxt<'tcx>) -> bool { - if !self.flags.get().intersects(AdtFlags::IS_DTORCK_VALID) { - self.calculate_dtorck(tcx) - } - self.flags.get().intersects(AdtFlags::IS_DTORCK) - } - - /// Returns whether this type is #[fundamental] for the purposes - /// of coherence checking. - #[inline] - pub fn is_fundamental(&self) -> bool { - self.flags.get().intersects(AdtFlags::IS_FUNDAMENTAL) - } - - #[inline] - pub fn is_simd(&self) -> bool { - self.flags.get().intersects(AdtFlags::IS_SIMD) - } - - /// Returns true if this is PhantomData. - #[inline] - pub fn is_phantom_data(&self) -> bool { - self.flags.get().intersects(AdtFlags::IS_PHANTOM_DATA) - } - - /// Returns whether this type has a destructor. - pub fn has_dtor(&self) -> bool { - match self.dtor_kind() { - NoDtor => false, - TraitDtor(..) => true - } - } - - /// Asserts this is a struct and returns the struct's unique - /// variant. - pub fn struct_variant(&self) -> &VariantDefData<'tcx, 'container> { - assert_eq!(self.adt_kind(), AdtKind::Struct); - &self.variants[0] - } - - #[inline] - pub fn type_scheme(&self, tcx: &TyCtxt<'tcx>) -> TypeScheme<'tcx> { - tcx.lookup_item_type(self.did) - } - - #[inline] - pub fn predicates(&self, tcx: &TyCtxt<'tcx>) -> GenericPredicates<'tcx> { - tcx.lookup_predicates(self.did) - } - - /// Returns an iterator over all fields contained - /// by this ADT. - #[inline] - pub fn all_fields(&self) -> - iter::FlatMap< - slice::Iter>, - slice::Iter>, - for<'s> fn(&'s VariantDefData<'tcx, 'container>) - -> slice::Iter<'s, FieldDefData<'tcx, 'container>> - > { - self.variants.iter().flat_map(VariantDefData::fields_iter) - } - - #[inline] - pub fn is_empty(&self) -> bool { - self.variants.is_empty() - } - - #[inline] - pub fn is_univariant(&self) -> bool { - self.variants.len() == 1 - } - - pub fn is_payloadfree(&self) -> bool { - !self.variants.is_empty() && - self.variants.iter().all(|v| v.fields.is_empty()) - } - - pub fn variant_with_id(&self, vid: DefId) -> &VariantDefData<'tcx, 'container> { - self.variants - .iter() - .find(|v| v.did == vid) - .expect("variant_with_id: unknown variant") - } - - pub fn variant_index_with_id(&self, vid: DefId) -> usize { - self.variants - .iter() - .position(|v| v.did == vid) - .expect("variant_index_with_id: unknown variant") - } - - pub fn variant_of_def(&self, def: Def) -> &VariantDefData<'tcx, 'container> { - match def { - Def::Variant(_, vid) => self.variant_with_id(vid), - Def::Struct(..) | Def::TyAlias(..) => self.struct_variant(), - _ => panic!("unexpected def {:?} in variant_of_def", def) - } - } - - pub fn destructor(&self) -> Option { - self.destructor.get() - } - - pub fn set_destructor(&self, dtor: DefId) { - self.destructor.set(Some(dtor)); - } - - pub fn dtor_kind(&self) -> DtorKind { - match self.destructor.get() { - Some(_) => { - TraitDtor(!self.flags.get().intersects(AdtFlags::IS_NO_DROP_FLAG)) - } - None => NoDtor, - } - } -} - -impl<'tcx, 'container> VariantDefData<'tcx, 'container> { - #[inline] - fn fields_iter(&self) -> slice::Iter> { - self.fields.iter() - } - - pub fn kind(&self) -> VariantKind { - self.kind - } - - pub fn is_tuple_struct(&self) -> bool { - self.kind() == VariantKind::Tuple - } - - #[inline] - pub fn find_field_named(&self, - name: ast::Name) - -> Option<&FieldDefData<'tcx, 'container>> { - self.fields.iter().find(|f| f.name == name) - } - - #[inline] - pub fn index_of_field_named(&self, - name: ast::Name) - -> Option { - self.fields.iter().position(|f| f.name == name) - } - - #[inline] - pub fn field_named(&self, name: ast::Name) -> &FieldDefData<'tcx, 'container> { - self.find_field_named(name).unwrap() - } -} - -impl<'tcx, 'container> FieldDefData<'tcx, 'container> { - pub fn new(did: DefId, - name: Name, - vis: hir::Visibility) -> Self { - FieldDefData { - did: did, - name: name, - vis: vis, - ty: ivar::TyIVar::new() - } - } - - pub fn ty(&self, tcx: &TyCtxt<'tcx>, subst: &Substs<'tcx>) -> Ty<'tcx> { - self.unsubst_ty().subst(tcx, subst) - } - - pub fn unsubst_ty(&self) -> Ty<'tcx> { - self.ty.unwrap(DepNode::FieldTy(self.did)) - } - - pub fn fulfill_ty(&self, ty: Ty<'container>) { - self.ty.fulfill(DepNode::FieldTy(self.did), ty); - } -} - -/// Records the substitutions used to translate the polytype for an -/// item into the monotype of an item reference. -#[derive(Clone)] -pub struct ItemSubsts<'tcx> { - pub substs: Substs<'tcx>, -} - -#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)] -pub enum ClosureKind { - // Warning: Ordering is significant here! The ordering is chosen - // because the trait Fn is a subtrait of FnMut and so in turn, and - // hence we order it so that Fn < FnMut < FnOnce. - Fn, - FnMut, - FnOnce, -} - -impl ClosureKind { - pub fn trait_did(&self, cx: &TyCtxt) -> DefId { - let result = match *self { - ClosureKind::Fn => cx.lang_items.require(FnTraitLangItem), - ClosureKind::FnMut => { - cx.lang_items.require(FnMutTraitLangItem) - } - ClosureKind::FnOnce => { - cx.lang_items.require(FnOnceTraitLangItem) - } - }; - match result { - Ok(trait_did) => trait_did, - Err(err) => cx.sess.fatal(&err[..]), - } - } - - /// True if this a type that impls this closure kind - /// must also implement `other`. - pub fn extends(self, other: ty::ClosureKind) -> bool { - match (self, other) { - (ClosureKind::Fn, ClosureKind::Fn) => true, - (ClosureKind::Fn, ClosureKind::FnMut) => true, - (ClosureKind::Fn, ClosureKind::FnOnce) => true, - (ClosureKind::FnMut, ClosureKind::FnMut) => true, - (ClosureKind::FnMut, ClosureKind::FnOnce) => true, - (ClosureKind::FnOnce, ClosureKind::FnOnce) => true, - _ => false, - } - } -} - -impl<'tcx> TyS<'tcx> { - /// Iterator that walks `self` and any types reachable from - /// `self`, in depth-first order. Note that just walks the types - /// that appear in `self`, it does not descend into the fields of - /// structs or variants. For example: - /// - /// ```notrust - /// isize => { isize } - /// Foo> => { Foo>, Bar, isize } - /// [isize] => { [isize], isize } - /// ``` - pub fn walk(&'tcx self) -> TypeWalker<'tcx> { - TypeWalker::new(self) - } - - /// Iterator that walks the immediate children of `self`. Hence - /// `Foo, u32>` yields the sequence `[Bar, u32]` - /// (but not `i32`, like `walk`). - pub fn walk_shallow(&'tcx self) -> IntoIter> { - walk::walk_shallow(self) - } - - /// Walks `ty` and any types appearing within `ty`, invoking the - /// callback `f` on each type. If the callback returns false, then the - /// children of the current type are ignored. - /// - /// Note: prefer `ty.walk()` where possible. - pub fn maybe_walk(&'tcx self, mut f: F) - where F : FnMut(Ty<'tcx>) -> bool - { - let mut walker = self.walk(); - while let Some(ty) = walker.next() { - if !f(ty) { - walker.skip_current_subtree(); - } - } - } -} - -impl<'tcx> ItemSubsts<'tcx> { - pub fn empty() -> ItemSubsts<'tcx> { - ItemSubsts { substs: Substs::empty() } - } - - pub fn is_noop(&self) -> bool { - self.substs.is_noop() - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum LvaluePreference { - PreferMutLvalue, - NoPreference -} - -impl LvaluePreference { - pub fn from_mutbl(m: hir::Mutability) -> Self { - match m { - hir::MutMutable => PreferMutLvalue, - hir::MutImmutable => NoPreference, - } - } -} - -/// Helper for looking things up in the various maps that are populated during -/// typeck::collect (e.g., `cx.impl_or_trait_items`, `cx.tcache`, etc). All of -/// these share the pattern that if the id is local, it should have been loaded -/// into the map by the `typeck::collect` phase. If the def-id is external, -/// then we have to go consult the crate loading code (and cache the result for -/// the future). -fn lookup_locally_or_in_crate_store(descr: &str, - def_id: DefId, - map: &M, - load_external: F) - -> M::Value where - M: MemoizationMap, - F: FnOnce() -> M::Value, -{ - map.memoize(def_id, || { - if def_id.is_local() { - panic!("No def'n found for {:?} in tcx.{}", def_id, descr); - } - load_external() - }) -} - -impl BorrowKind { - pub fn from_mutbl(m: hir::Mutability) -> BorrowKind { - match m { - hir::MutMutable => MutBorrow, - hir::MutImmutable => ImmBorrow, - } - } - - /// Returns a mutability `m` such that an `&m T` pointer could be used to obtain this borrow - /// kind. Because borrow kinds are richer than mutabilities, we sometimes have to pick a - /// mutability that is stronger than necessary so that it at least *would permit* the borrow in - /// question. - pub fn to_mutbl_lossy(self) -> hir::Mutability { - match self { - MutBorrow => hir::MutMutable, - ImmBorrow => hir::MutImmutable, - - // We have no type corresponding to a unique imm borrow, so - // use `&mut`. It gives all the capabilities of an `&uniq` - // and hence is a safe "over approximation". - UniqueImmBorrow => hir::MutMutable, - } - } - - pub fn to_user_str(&self) -> &'static str { - match *self { - MutBorrow => "mutable", - ImmBorrow => "immutable", - UniqueImmBorrow => "uniquely immutable", - } - } -} - -impl<'tcx> TyCtxt<'tcx> { - pub fn node_id_to_type(&self, id: NodeId) -> Ty<'tcx> { - match self.node_id_to_type_opt(id) { - Some(ty) => ty, - None => self.sess.bug( - &format!("node_id_to_type: no type for node `{}`", - self.map.node_to_string(id))) - } - } - - pub fn node_id_to_type_opt(&self, id: NodeId) -> Option> { - self.tables.borrow().node_types.get(&id).cloned() - } - - pub fn node_id_item_substs(&self, id: NodeId) -> ItemSubsts<'tcx> { - match self.tables.borrow().item_substs.get(&id) { - None => ItemSubsts::empty(), - Some(ts) => ts.clone(), - } - } - - // Returns the type of a pattern as a monotype. Like @expr_ty, this function - // doesn't provide type parameter substitutions. - pub fn pat_ty(&self, pat: &hir::Pat) -> Ty<'tcx> { - self.node_id_to_type(pat.id) - } - pub fn pat_ty_opt(&self, pat: &hir::Pat) -> Option> { - self.node_id_to_type_opt(pat.id) - } - - // Returns the type of an expression as a monotype. - // - // NB (1): This is the PRE-ADJUSTMENT TYPE for the expression. That is, in - // some cases, we insert `AutoAdjustment` annotations such as auto-deref or - // auto-ref. The type returned by this function does not consider such - // adjustments. See `expr_ty_adjusted()` instead. - // - // NB (2): This type doesn't provide type parameter substitutions; e.g. if you - // ask for the type of "id" in "id(3)", it will return "fn(&isize) -> isize" - // instead of "fn(ty) -> T with T = isize". - pub fn expr_ty(&self, expr: &hir::Expr) -> Ty<'tcx> { - self.node_id_to_type(expr.id) - } - - pub fn expr_ty_opt(&self, expr: &hir::Expr) -> Option> { - self.node_id_to_type_opt(expr.id) - } - - /// Returns the type of `expr`, considering any `AutoAdjustment` - /// entry recorded for that expression. - /// - /// It would almost certainly be better to store the adjusted ty in with - /// the `AutoAdjustment`, but I opted not to do this because it would - /// require serializing and deserializing the type and, although that's not - /// hard to do, I just hate that code so much I didn't want to touch it - /// unless it was to fix it properly, which seemed a distraction from the - /// thread at hand! -nmatsakis - pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> Ty<'tcx> { - self.expr_ty(expr) - .adjust(self, expr.span, expr.id, - self.tables.borrow().adjustments.get(&expr.id), - |method_call| { - self.tables.borrow().method_map.get(&method_call).map(|method| method.ty) - }) - } - - pub fn expr_ty_adjusted_opt(&self, expr: &hir::Expr) -> Option> { - self.expr_ty_opt(expr).map(|t| t.adjust(self, - expr.span, - expr.id, - self.tables.borrow().adjustments.get(&expr.id), - |method_call| { - self.tables.borrow().method_map.get(&method_call).map(|method| method.ty) - })) - } - - pub fn expr_span(&self, id: NodeId) -> Span { - match self.map.find(id) { - Some(ast_map::NodeExpr(e)) => { - e.span - } - Some(f) => { - self.sess.bug(&format!("Node id {} is not an expr: {:?}", - id, f)); - } - None => { - self.sess.bug(&format!("Node id {} is not present \ - in the node map", id)); - } - } - } - - pub fn local_var_name_str(&self, id: NodeId) -> InternedString { - match self.map.find(id) { - Some(ast_map::NodeLocal(pat)) => { - match pat.node { - PatKind::Ident(_, ref path1, _) => path1.node.name.as_str(), - _ => { - self.sess.bug(&format!("Variable id {} maps to {:?}, not local", id, pat)); - }, - } - }, - r => self.sess.bug(&format!("Variable id {} maps to {:?}, not local", id, r)), - } - } - - pub fn resolve_expr(&self, expr: &hir::Expr) -> Def { - match self.def_map.borrow().get(&expr.id) { - Some(def) => def.full_def(), - None => { - self.sess.span_bug(expr.span, &format!( - "no def-map entry for expr {}", expr.id)); - } - } - } - - pub fn expr_is_lval(&self, expr: &hir::Expr) -> bool { - match expr.node { - hir::ExprPath(..) => { - // We can't use resolve_expr here, as this needs to run on broken - // programs. We don't need to through - associated items are all - // rvalues. - match self.def_map.borrow().get(&expr.id) { - Some(&def::PathResolution { - base_def: Def::Static(..), .. - }) | Some(&def::PathResolution { - base_def: Def::Upvar(..), .. - }) | Some(&def::PathResolution { - base_def: Def::Local(..), .. - }) => { - true - } - Some(&def::PathResolution { base_def: Def::Err, .. })=> true, - Some(..) => false, - None => self.sess.span_bug(expr.span, &format!( - "no def for path {}", expr.id)) - } - } - - hir::ExprType(ref e, _) => { - self.expr_is_lval(e) - } - - hir::ExprUnary(hir::UnDeref, _) | - hir::ExprField(..) | - hir::ExprTupField(..) | - hir::ExprIndex(..) => { - true - } - - hir::ExprCall(..) | - hir::ExprMethodCall(..) | - hir::ExprStruct(..) | - hir::ExprTup(..) | - hir::ExprIf(..) | - hir::ExprMatch(..) | - hir::ExprClosure(..) | - hir::ExprBlock(..) | - hir::ExprRepeat(..) | - hir::ExprVec(..) | - hir::ExprBreak(..) | - hir::ExprAgain(..) | - hir::ExprRet(..) | - hir::ExprWhile(..) | - hir::ExprLoop(..) | - hir::ExprAssign(..) | - hir::ExprInlineAsm(..) | - hir::ExprAssignOp(..) | - hir::ExprLit(_) | - hir::ExprUnary(..) | - hir::ExprBox(..) | - hir::ExprAddrOf(..) | - hir::ExprBinary(..) | - hir::ExprCast(..) => { - false - } - } - } - - pub fn provided_trait_methods(&self, id: DefId) -> Vec>> { - if let Some(id) = self.map.as_local_node_id(id) { - if let ItemTrait(_, _, _, ref ms) = self.map.expect_item(id).node { - ms.iter().filter_map(|ti| { - if let hir::MethodTraitItem(_, Some(_)) = ti.node { - match self.impl_or_trait_item(self.map.local_def_id(ti.id)) { - MethodTraitItem(m) => Some(m), - _ => { - self.sess.bug("provided_trait_methods(): \ - non-method item found from \ - looking up provided method?!") - } - } - } else { - None - } - }).collect() - } else { - self.sess.bug(&format!("provided_trait_methods: `{:?}` is not a trait", id)) - } - } else { - self.sess.cstore.provided_trait_methods(self, id) - } - } - - pub fn associated_consts(&self, id: DefId) -> Vec>> { - if let Some(id) = self.map.as_local_node_id(id) { - match self.map.expect_item(id).node { - ItemTrait(_, _, _, ref tis) => { - tis.iter().filter_map(|ti| { - if let hir::ConstTraitItem(_, _) = ti.node { - match self.impl_or_trait_item(self.map.local_def_id(ti.id)) { - ConstTraitItem(ac) => Some(ac), - _ => { - self.sess.bug("associated_consts(): \ - non-const item found from \ - looking up a constant?!") - } - } - } else { - None - } - }).collect() - } - ItemImpl(_, _, _, _, _, ref iis) => { - iis.iter().filter_map(|ii| { - if let hir::ImplItemKind::Const(_, _) = ii.node { - match self.impl_or_trait_item(self.map.local_def_id(ii.id)) { - ConstTraitItem(ac) => Some(ac), - _ => { - self.sess.bug("associated_consts(): \ - non-const item found from \ - looking up a constant?!") - } - } - } else { - None - } - }).collect() - } - _ => { - self.sess.bug(&format!("associated_consts: `{:?}` is not a trait \ - or impl", id)) - } - } - } else { - self.sess.cstore.associated_consts(self, id) - } - } - - pub fn trait_impl_polarity(&self, id: DefId) -> Option { - if let Some(id) = self.map.as_local_node_id(id) { - match self.map.find(id) { - Some(ast_map::NodeItem(item)) => { - match item.node { - hir::ItemImpl(_, polarity, _, _, _, _) => Some(polarity), - _ => None - } - } - _ => None - } - } else { - self.sess.cstore.impl_polarity(id) - } - } - - pub fn custom_coerce_unsized_kind(&self, did: DefId) -> adjustment::CustomCoerceUnsized { - self.custom_coerce_unsized_kinds.memoize(did, || { - let (kind, src) = if did.krate != LOCAL_CRATE { - (self.sess.cstore.custom_coerce_unsized_kind(did), "external") - } else { - (None, "local") - }; - - match kind { - Some(kind) => kind, - None => { - self.sess.bug(&format!("custom_coerce_unsized_kind: \ - {} impl `{}` is missing its kind", - src, self.item_path_str(did))); - } - } - }) - } - - pub fn impl_or_trait_item(&self, id: DefId) -> ImplOrTraitItem<'tcx> { - lookup_locally_or_in_crate_store( - "impl_or_trait_items", id, &self.impl_or_trait_items, - || self.sess.cstore.impl_or_trait_item(self, id) - .expect("missing ImplOrTraitItem in metadata")) - } - - pub fn trait_item_def_ids(&self, id: DefId) -> Rc> { - lookup_locally_or_in_crate_store( - "trait_item_def_ids", id, &self.trait_item_def_ids, - || Rc::new(self.sess.cstore.trait_item_def_ids(id))) - } - - /// Returns the trait-ref corresponding to a given impl, or None if it is - /// an inherent impl. - pub fn impl_trait_ref(&self, id: DefId) -> Option> { - lookup_locally_or_in_crate_store( - "impl_trait_refs", id, &self.impl_trait_refs, - || self.sess.cstore.impl_trait_ref(self, id)) - } - - /// Returns whether this DefId refers to an impl - pub fn is_impl(&self, id: DefId) -> bool { - if let Some(id) = self.map.as_local_node_id(id) { - if let Some(ast_map::NodeItem( - &hir::Item { node: hir::ItemImpl(..), .. })) = self.map.find(id) { - true - } else { - false - } - } else { - self.sess.cstore.is_impl(id) - } - } - - pub fn trait_ref_to_def_id(&self, tr: &hir::TraitRef) -> DefId { - self.def_map.borrow().get(&tr.ref_id).expect("no def-map entry for trait").def_id() - } - - pub fn def_key(&self, id: DefId) -> ast_map::DefKey { - if id.is_local() { - self.map.def_key(id) - } else { - self.sess.cstore.def_key(id) - } - } - - /// Returns the `DefPath` of an item. Note that if `id` is not - /// local to this crate -- or is inlined into this crate -- the - /// result will be a non-local `DefPath`. - pub fn def_path(&self, id: DefId) -> ast_map::DefPath { - if id.is_local() { - self.map.def_path(id) - } else { - self.sess.cstore.relative_def_path(id) - } - } - - pub fn with_path(&self, id: DefId, f: F) -> T where - F: FnOnce(ast_map::PathElems) -> T, - { - if let Some(id) = self.map.as_local_node_id(id) { - self.map.with_path(id, f) - } else { - let mut path: Vec<_>; - if let Some(extern_crate) = self.sess.cstore.extern_crate(id.krate) { - if !extern_crate.direct { - // this comes from some crate that we don't have a direct - // path to; we'll settle for just prepending the name of - // the crate. - path = self.sess.cstore.extern_item_path(id) - } else { - // start with the path to the extern crate, then - // add the relative path to the actual item - fn collector(elems: ast_map::PathElems) -> Vec { - elems.collect() - } - path = self.with_path(extern_crate.def_id, collector); - path.extend(self.sess.cstore.relative_item_path(id)); - } - } else { - // if this was injected, just make a path with name of crate - path = self.sess.cstore.extern_item_path(id); - } - f(path.iter().cloned().chain(LinkedPath::empty())) - } - } - - pub fn item_name(&self, id: DefId) -> ast::Name { - if let Some(id) = self.map.as_local_node_id(id) { - self.map.get_path_elem(id).name() - } else { - self.sess.cstore.item_name(id) - } - } - - // Register a given item type - pub fn register_item_type(&self, did: DefId, ty: TypeScheme<'tcx>) { - self.tcache.borrow_mut().insert(did, ty); - } - - // If the given item is in an external crate, looks up its type and adds it to - // the type cache. Returns the type parameters and type. - pub fn lookup_item_type(&self, did: DefId) -> TypeScheme<'tcx> { - lookup_locally_or_in_crate_store( - "tcache", did, &self.tcache, - || self.sess.cstore.item_type(self, did)) - } - - /// Given the did of a trait, returns its canonical trait ref. - pub fn lookup_trait_def(&self, did: DefId) -> &'tcx TraitDef<'tcx> { - lookup_locally_or_in_crate_store( - "trait_defs", did, &self.trait_defs, - || self.alloc_trait_def(self.sess.cstore.trait_def(self, did)) - ) - } - - /// Given the did of an ADT, return a master reference to its - /// definition. Unless you are planning on fulfilling the ADT's fields, - /// use lookup_adt_def instead. - pub fn lookup_adt_def_master(&self, did: DefId) -> AdtDefMaster<'tcx> { - lookup_locally_or_in_crate_store( - "adt_defs", did, &self.adt_defs, - || self.sess.cstore.adt_def(self, did) - ) - } - - /// Given the did of an ADT, return a reference to its definition. - pub fn lookup_adt_def(&self, did: DefId) -> AdtDef<'tcx> { - // when reverse-variance goes away, a transmute:: - // would be needed here. - self.lookup_adt_def_master(did) - } - - /// Given the did of an item, returns its full set of predicates. - pub fn lookup_predicates(&self, did: DefId) -> GenericPredicates<'tcx> { - lookup_locally_or_in_crate_store( - "predicates", did, &self.predicates, - || self.sess.cstore.item_predicates(self, did)) - } - - /// Given the did of a trait, returns its superpredicates. - pub fn lookup_super_predicates(&self, did: DefId) -> GenericPredicates<'tcx> { - lookup_locally_or_in_crate_store( - "super_predicates", did, &self.super_predicates, - || self.sess.cstore.item_super_predicates(self, did)) - } - - /// If `type_needs_drop` returns true, then `ty` is definitely - /// non-copy and *might* have a destructor attached; if it returns - /// false, then `ty` definitely has no destructor (i.e. no drop glue). - /// - /// (Note that this implies that if `ty` has a destructor attached, - /// then `type_needs_drop` will definitely return `true` for `ty`.) - pub fn type_needs_drop_given_env<'a>(&self, - ty: Ty<'tcx>, - param_env: &ty::ParameterEnvironment<'a,'tcx>) -> bool { - // Issue #22536: We first query type_moves_by_default. It sees a - // normalized version of the type, and therefore will definitely - // know whether the type implements Copy (and thus needs no - // cleanup/drop/zeroing) ... - let implements_copy = !ty.moves_by_default(param_env, DUMMY_SP); - - if implements_copy { return false; } - - // ... (issue #22536 continued) but as an optimization, still use - // prior logic of asking if the `needs_drop` bit is set; we need - // not zero non-Copy types if they have no destructor. - - // FIXME(#22815): Note that calling `ty::type_contents` is a - // conservative heuristic; it may report that `needs_drop` is set - // when actual type does not actually have a destructor associated - // with it. But since `ty` absolutely did not have the `Copy` - // bound attached (see above), it is sound to treat it as having a - // destructor (e.g. zero its memory on move). - - let contents = ty.type_contents(self); - debug!("type_needs_drop ty={:?} contents={:?}", ty, contents); - contents.needs_drop(self) - } - - /// Get the attributes of a definition. - pub fn get_attrs(&self, did: DefId) -> Cow<'tcx, [ast::Attribute]> { - if let Some(id) = self.map.as_local_node_id(did) { - Cow::Borrowed(self.map.attrs(id)) - } else { - Cow::Owned(self.sess.cstore.item_attrs(did)) - } - } - - /// Determine whether an item is annotated with an attribute - pub fn has_attr(&self, did: DefId, attr: &str) -> bool { - self.get_attrs(did).iter().any(|item| item.check_name(attr)) - } - - /// Determine whether an item is annotated with `#[repr(packed)]` - pub fn lookup_packed(&self, did: DefId) -> bool { - self.lookup_repr_hints(did).contains(&attr::ReprPacked) - } - - /// Determine whether an item is annotated with `#[simd]` - pub fn lookup_simd(&self, did: DefId) -> bool { - self.has_attr(did, "simd") - || self.lookup_repr_hints(did).contains(&attr::ReprSimd) - } - - pub fn item_variances(&self, item_id: DefId) -> Rc { - lookup_locally_or_in_crate_store( - "item_variance_map", item_id, &self.item_variance_map, - || Rc::new(self.sess.cstore.item_variances(item_id))) - } - - pub fn trait_has_default_impl(&self, trait_def_id: DefId) -> bool { - self.populate_implementations_for_trait_if_necessary(trait_def_id); - - let def = self.lookup_trait_def(trait_def_id); - def.flags.get().intersects(TraitFlags::HAS_DEFAULT_IMPL) - } - - /// Records a trait-to-implementation mapping. - pub fn record_trait_has_default_impl(&self, trait_def_id: DefId) { - let def = self.lookup_trait_def(trait_def_id); - def.flags.set(def.flags.get() | TraitFlags::HAS_DEFAULT_IMPL) - } - - /// Load primitive inherent implementations if necessary - pub fn populate_implementations_for_primitive_if_necessary(&self, - primitive_def_id: DefId) { - if primitive_def_id.is_local() { - return - } - - // The primitive is not local, hence we are reading this out - // of metadata. - let _ignore = self.dep_graph.in_ignore(); - - if self.populated_external_primitive_impls.borrow().contains(&primitive_def_id) { - return - } - - debug!("populate_implementations_for_primitive_if_necessary: searching for {:?}", - primitive_def_id); - - let impl_items = self.sess.cstore.impl_items(primitive_def_id); - - // Store the implementation info. - self.impl_items.borrow_mut().insert(primitive_def_id, impl_items); - self.populated_external_primitive_impls.borrow_mut().insert(primitive_def_id); - } - - /// Populates the type context with all the inherent implementations for - /// the given type if necessary. - pub fn populate_inherent_implementations_for_type_if_necessary(&self, - type_id: DefId) { - if type_id.is_local() { - return - } - - // The type is not local, hence we are reading this out of - // metadata and don't need to track edges. - let _ignore = self.dep_graph.in_ignore(); - - if self.populated_external_types.borrow().contains(&type_id) { - return - } - - debug!("populate_inherent_implementations_for_type_if_necessary: searching for {:?}", - type_id); - - let inherent_impls = self.sess.cstore.inherent_implementations_for_type(type_id); - for &impl_def_id in &inherent_impls { - // Store the implementation info. - let impl_items = self.sess.cstore.impl_items(impl_def_id); - self.impl_items.borrow_mut().insert(impl_def_id, impl_items); - } - - self.inherent_impls.borrow_mut().insert(type_id, Rc::new(inherent_impls)); - self.populated_external_types.borrow_mut().insert(type_id); - } - - /// Populates the type context with all the implementations for the given - /// trait if necessary. - pub fn populate_implementations_for_trait_if_necessary(&self, trait_id: DefId) { - if trait_id.is_local() { - return - } - - // The type is not local, hence we are reading this out of - // metadata and don't need to track edges. - let _ignore = self.dep_graph.in_ignore(); - - let def = self.lookup_trait_def(trait_id); - if def.flags.get().intersects(TraitFlags::IMPLS_VALID) { - return; - } - - debug!("populate_implementations_for_trait_if_necessary: searching for {:?}", def); - - if self.sess.cstore.is_defaulted_trait(trait_id) { - self.record_trait_has_default_impl(trait_id); - } - - for impl_def_id in self.sess.cstore.implementations_of_trait(trait_id) { - let impl_items = self.sess.cstore.impl_items(impl_def_id); - let trait_ref = self.impl_trait_ref(impl_def_id).unwrap(); - - // Record the trait->implementation mapping. - if let Some(parent) = self.sess.cstore.impl_parent(impl_def_id) { - def.record_remote_impl(self, impl_def_id, trait_ref, parent); - } else { - def.record_remote_impl(self, impl_def_id, trait_ref, trait_id); - } - - // For any methods that use a default implementation, add them to - // the map. This is a bit unfortunate. - for impl_item_def_id in &impl_items { - let method_def_id = impl_item_def_id.def_id(); - // load impl items eagerly for convenience - // FIXME: we may want to load these lazily - self.impl_or_trait_item(method_def_id); - } - - // Store the implementation info. - self.impl_items.borrow_mut().insert(impl_def_id, impl_items); - } - - def.flags.set(def.flags.get() | TraitFlags::IMPLS_VALID); - } - - pub fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind { - Tables::closure_kind(&self.tables, self, def_id) - } - - pub fn closure_type(&self, - def_id: DefId, - substs: &ClosureSubsts<'tcx>) - -> ty::ClosureTy<'tcx> - { - Tables::closure_type(&self.tables, self, def_id, substs) - } - - /// Given the def_id of an impl, return the def_id of the trait it implements. - /// If it implements no trait, return `None`. - pub fn trait_id_of_impl(&self, def_id: DefId) -> Option { - self.impl_trait_ref(def_id).map(|tr| tr.def_id) - } - - /// If the given def ID describes a method belonging to an impl, return the - /// ID of the impl that the method belongs to. Otherwise, return `None`. - pub fn impl_of_method(&self, def_id: DefId) -> Option { - if def_id.krate != LOCAL_CRATE { - return self.sess.cstore.impl_or_trait_item(self, def_id).and_then(|item| { - match item.container() { - TraitContainer(_) => None, - ImplContainer(def_id) => Some(def_id), - } - }); - } - match self.impl_or_trait_items.borrow().get(&def_id).cloned() { - Some(trait_item) => { - match trait_item.container() { - TraitContainer(_) => None, - ImplContainer(def_id) => Some(def_id), - } - } - None => None - } - } - - /// If the given def ID describes an item belonging to a trait (either a - /// default method or an implementation of a trait method), return the ID of - /// the trait that the method belongs to. Otherwise, return `None`. - pub fn trait_of_item(&self, def_id: DefId) -> Option { - if def_id.krate != LOCAL_CRATE { - return self.sess.cstore.trait_of_item(self, def_id); - } - match self.impl_or_trait_items.borrow().get(&def_id).cloned() { - Some(impl_or_trait_item) => { - match impl_or_trait_item.container() { - TraitContainer(def_id) => Some(def_id), - ImplContainer(def_id) => self.trait_id_of_impl(def_id), - } - } - None => None - } - } - - /// If the given def ID describes an item belonging to a trait, (either a - /// default method or an implementation of a trait method), return the ID of - /// the method inside trait definition (this means that if the given def ID - /// is already that of the original trait method, then the return value is - /// the same). - /// Otherwise, return `None`. - pub fn trait_item_of_item(&self, def_id: DefId) -> Option { - let impl_item = match self.impl_or_trait_items.borrow().get(&def_id) { - Some(m) => m.clone(), - None => return None, - }; - let name = impl_item.name(); - match self.trait_of_item(def_id) { - Some(trait_did) => { - self.trait_items(trait_did).iter() - .find(|item| item.name() == name) - .map(|item| item.id()) - } - None => None - } - } - - /// Construct a parameter environment suitable for static contexts or other contexts where there - /// are no free type/lifetime parameters in scope. - pub fn empty_parameter_environment<'a>(&'a self) - -> ParameterEnvironment<'a,'tcx> { - - // for an empty parameter environment, there ARE no free - // regions, so it shouldn't matter what we use for the free id - let free_id_outlive = self.region_maps.node_extent(ast::DUMMY_NODE_ID); - ty::ParameterEnvironment { tcx: self, - free_substs: Substs::empty(), - caller_bounds: Vec::new(), - implicit_region_bound: ty::ReEmpty, - selection_cache: traits::SelectionCache::new(), - evaluation_cache: traits::EvaluationCache::new(), - free_id_outlive: free_id_outlive } - } - - /// Constructs and returns a substitution that can be applied to move from - /// the "outer" view of a type or method to the "inner" view. - /// In general, this means converting from bound parameters to - /// free parameters. Since we currently represent bound/free type - /// parameters in the same way, this only has an effect on regions. - pub fn construct_free_substs(&self, generics: &Generics<'tcx>, - free_id_outlive: CodeExtent) -> Substs<'tcx> { - // map T => T - let mut types = VecPerParamSpace::empty(); - for def in generics.types.as_slice() { - debug!("construct_parameter_environment(): push_types_from_defs: def={:?}", - def); - types.push(def.space, self.mk_param_from_def(def)); - } - - // map bound 'a => free 'a - let mut regions = VecPerParamSpace::empty(); - for def in generics.regions.as_slice() { - let region = - ReFree(FreeRegion { scope: free_id_outlive, - bound_region: BrNamed(def.def_id, def.name) }); - debug!("push_region_params {:?}", region); - regions.push(def.space, region); - } - - Substs { - types: types, - regions: regions, - } - } - - /// See `ParameterEnvironment` struct def'n for details. - /// If you were using `free_id: NodeId`, you might try `self.region_maps.item_extent(free_id)` - /// for the `free_id_outlive` parameter. (But note that that is not always quite right.) - pub fn construct_parameter_environment<'a>(&'a self, - span: Span, - generics: &ty::Generics<'tcx>, - generic_predicates: &ty::GenericPredicates<'tcx>, - free_id_outlive: CodeExtent) - -> ParameterEnvironment<'a, 'tcx> - { - // - // Construct the free substs. - // - - let free_substs = self.construct_free_substs(generics, free_id_outlive); - - // - // Compute the bounds on Self and the type parameters. - // - - let bounds = generic_predicates.instantiate(self, &free_substs); - let bounds = self.liberate_late_bound_regions(free_id_outlive, &ty::Binder(bounds)); - let predicates = bounds.predicates.into_vec(); - - // Finally, we have to normalize the bounds in the environment, in - // case they contain any associated type projections. This process - // can yield errors if the put in illegal associated types, like - // `::Bar` where `i32` does not implement `Foo`. We - // report these errors right here; this doesn't actually feel - // right to me, because constructing the environment feels like a - // kind of a "idempotent" action, but I'm not sure where would be - // a better place. In practice, we construct environments for - // every fn once during type checking, and we'll abort if there - // are any errors at that point, so after type checking you can be - // sure that this will succeed without errors anyway. - // - - let unnormalized_env = ty::ParameterEnvironment { - tcx: self, - free_substs: free_substs, - implicit_region_bound: ty::ReScope(free_id_outlive), - caller_bounds: predicates, - selection_cache: traits::SelectionCache::new(), - evaluation_cache: traits::EvaluationCache::new(), - free_id_outlive: free_id_outlive, - }; - - let cause = traits::ObligationCause::misc(span, free_id_outlive.node_id(&self.region_maps)); - traits::normalize_param_env_or_error(unnormalized_env, cause) - } - - pub fn is_method_call(&self, expr_id: NodeId) -> bool { - self.tables.borrow().method_map.contains_key(&MethodCall::expr(expr_id)) - } - - pub fn is_overloaded_autoderef(&self, expr_id: NodeId, autoderefs: u32) -> bool { - self.tables.borrow().method_map.contains_key(&MethodCall::autoderef(expr_id, - autoderefs)) - } - - pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option { - Some(self.tables.borrow().upvar_capture_map.get(&upvar_id).unwrap().clone()) - } - - pub fn visit_all_items_in_krate(&self, - dep_node_fn: F, - visitor: &mut V) - where F: FnMut(DefId) -> DepNode, V: Visitor<'tcx> - { - dep_graph::visit_all_items_in_krate(self, dep_node_fn, visitor); - } - - /// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err` - /// with the name of the crate containing the impl. - pub fn span_of_impl(&self, impl_did: DefId) -> Result { - if impl_did.is_local() { - let node_id = self.map.as_local_node_id(impl_did).unwrap(); - Ok(self.map.span(node_id)) - } else { - Err(self.sess.cstore.crate_name(impl_did.krate)) - } - } -} - -/// The category of explicit self. -#[derive(Clone, Copy, Eq, PartialEq, Debug)] -pub enum ExplicitSelfCategory { - Static, - ByValue, - ByReference(Region, hir::Mutability), - ByBox, -} - -/// A free variable referred to in a function. -#[derive(Copy, Clone, RustcEncodable, RustcDecodable)] -pub struct Freevar { - /// The variable being accessed free. - pub def: Def, - - // First span where it is accessed (there can be multiple). - pub span: Span -} - -pub type FreevarMap = NodeMap>; - -pub type CaptureModeMap = NodeMap; - -// Trait method resolution -pub type TraitMap = NodeMap>; - -// Map from the NodeId of a glob import to a list of items which are actually -// imported. -pub type GlobMap = HashMap>; - -impl<'tcx> TyCtxt<'tcx> { - pub fn with_freevars(&self, fid: NodeId, f: F) -> T where - F: FnOnce(&[Freevar]) -> T, - { - match self.freevars.borrow().get(&fid) { - None => f(&[]), - Some(d) => f(&d[..]) - } - } -} diff --git a/src/librustc/middle/ty/outlives.rs b/src/librustc/middle/ty/outlives.rs deleted file mode 100644 index 9439180a6cd..00000000000 --- a/src/librustc/middle/ty/outlives.rs +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// The outlines relation `T: 'a` or `'a: 'b`. This code frequently -// refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that -// RFC for reference. - -use middle::infer::InferCtxt; -use middle::ty::{self, Ty, TypeFoldable}; - -#[derive(Debug)] -pub enum Component<'tcx> { - Region(ty::Region), - Param(ty::ParamTy), - UnresolvedInferenceVariable(ty::InferTy), - - // Projections like `T::Foo` are tricky because a constraint like - // `T::Foo: 'a` can be satisfied in so many ways. There may be a - // where-clause that says `T::Foo: 'a`, or the defining trait may - // include a bound like `type Foo: 'static`, or -- in the most - // conservative way -- we can prove that `T: 'a` (more generally, - // that all components in the projection outlive `'a`). This code - // is not in a position to judge which is the best technique, so - // we just product the projection as a component and leave it to - // the consumer to decide (but see `EscapingProjection` below). - Projection(ty::ProjectionTy<'tcx>), - - // In the case where a projection has escaping regions -- meaning - // regions bound within the type itself -- we always use - // the most conservative rule, which requires that all components - // outlive the bound. So for example if we had a type like this: - // - // for<'a> Trait1< >::Foo > - // ~~~~~~~~~~~~~~~~~~~~~~~~~ - // - // then the inner projection (underlined) has an escaping region - // `'a`. We consider that outer trait `'c` to meet a bound if `'b` - // outlives `'b: 'c`, and we don't consider whether the trait - // declares that `Foo: 'static` etc. Therefore, we just return the - // free components of such a projection (in this case, `'b`). - // - // However, in the future, we may want to get smarter, and - // actually return a "higher-ranked projection" here. Therefore, - // we mark that these components are part of an escaping - // projection, so that implied bounds code can avoid relying on - // them. This gives us room to improve the regionck reasoning in - // the future without breaking backwards compat. - EscapingProjection(Vec>), -} - -/// Returns all the things that must outlive `'a` for the condition -/// `ty0: 'a` to hold. -pub fn components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, - ty0: Ty<'tcx>) - -> Vec> { - let mut components = vec![]; - compute_components(infcx, ty0, &mut components); - debug!("components({:?}) = {:?}", ty0, components); - components -} - -fn compute_components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, - ty: Ty<'tcx>, - out: &mut Vec>) { - // Descend through the types, looking for the various "base" - // components and collecting them into `out`. This is not written - // with `collect()` because of the need to sometimes skip subtrees - // in the `subtys` iterator (e.g., when encountering a - // projection). - match ty.sty { - ty::TyClosure(_, ref substs) => { - // FIXME(#27086). We do not accumulate from substs, since they - // don't represent reachable data. This means that, in - // practice, some of the lifetime parameters might not - // be in scope when the body runs, so long as there is - // no reachable data with that lifetime. For better or - // worse, this is consistent with fn types, however, - // which can also encapsulate data in this fashion - // (though it's somewhat harder, and typically - // requires virtual dispatch). - // - // Note that changing this (in a naive way, at least) - // causes regressions for what appears to be perfectly - // reasonable code like this: - // - // ``` - // fn foo<'a>(p: &Data<'a>) { - // bar(|q: &mut Parser| q.read_addr()) - // } - // fn bar(p: Box) { - // } - // ``` - // - // Note that `p` (and `'a`) are not used in the - // closure at all, but to meet the requirement that - // the closure type `C: 'static` (so it can be coerced - // to the object type), we get the requirement that - // `'a: 'static` since `'a` appears in the closure - // type `C`. - // - // A smarter fix might "prune" unused `func_substs` -- - // this would avoid breaking simple examples like - // this, but would still break others (which might - // indeed be invalid, depending on your POV). Pruning - // would be a subtle process, since we have to see - // what func/type parameters are used and unused, - // taking into consideration UFCS and so forth. - - for &upvar_ty in &substs.upvar_tys { - compute_components(infcx, upvar_ty, out); - } - } - - // OutlivesTypeParameterEnv -- the actual checking that `X:'a` - // is implied by the environment is done in regionck. - ty::TyParam(p) => { - out.push(Component::Param(p)); - } - - // For projections, we prefer to generate an obligation like - // `>::Foo: 'a`, because this gives the - // regionck more ways to prove that it holds. However, - // regionck is not (at least currently) prepared to deal with - // higher-ranked regions that may appear in the - // trait-ref. Therefore, if we see any higher-ranke regions, - // we simply fallback to the most restrictive rule, which - // requires that `Pi: 'a` for all `i`. - ty::TyProjection(ref data) => { - if !data.has_escaping_regions() { - // best case: no escaping regions, so push the - // projection and skip the subtree (thus generating no - // constraints for Pi). This defers the choice between - // the rules OutlivesProjectionEnv, - // OutlivesProjectionTraitDef, and - // OutlivesProjectionComponents to regionck. - out.push(Component::Projection(*data)); - } else { - // fallback case: hard code - // OutlivesProjectionComponents. Continue walking - // through and constrain Pi. - let subcomponents = capture_components(infcx, ty); - out.push(Component::EscapingProjection(subcomponents)); - } - } - - // If we encounter an inference variable, try to resolve it - // and proceed with resolved version. If we cannot resolve it, - // then record the unresolved variable as a component. - ty::TyInfer(_) => { - let ty = infcx.resolve_type_vars_if_possible(&ty); - if let ty::TyInfer(infer_ty) = ty.sty { - out.push(Component::UnresolvedInferenceVariable(infer_ty)); - } else { - compute_components(infcx, ty, out); - } - } - - // Most types do not introduce any region binders, nor - // involve any other subtle cases, and so the WF relation - // simply constraints any regions referenced directly by - // the type and then visits the types that are lexically - // contained within. (The comments refer to relevant rules - // from RFC1214.) - ty::TyBool | // OutlivesScalar - ty::TyChar | // OutlivesScalar - ty::TyInt(..) | // OutlivesScalar - ty::TyUint(..) | // OutlivesScalar - ty::TyFloat(..) | // OutlivesScalar - ty::TyEnum(..) | // OutlivesNominalType - ty::TyStruct(..) | // OutlivesNominalType - ty::TyBox(..) | // OutlivesNominalType (ish) - ty::TyStr | // OutlivesScalar (ish) - ty::TyArray(..) | // ... - ty::TySlice(..) | // ... - ty::TyRawPtr(..) | // ... - ty::TyRef(..) | // OutlivesReference - ty::TyTuple(..) | // ... - ty::TyFnDef(..) | // OutlivesFunction (*) - ty::TyFnPtr(_) | // OutlivesFunction (*) - ty::TyTrait(..) | // OutlivesObject, OutlivesFragment (*) - ty::TyError => { - // (*) Bare functions and traits are both binders. In the - // RFC, this means we would add the bound regions to the - // "bound regions list". In our representation, no such - // list is maintained explicitly, because bound regions - // themselves can be readily identified. - - push_region_constraints(out, ty.regions()); - for subty in ty.walk_shallow() { - compute_components(infcx, subty, out); - } - } - } -} - -fn capture_components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, - ty: Ty<'tcx>) - -> Vec> { - let mut temp = vec![]; - push_region_constraints(&mut temp, ty.regions()); - for subty in ty.walk_shallow() { - compute_components(infcx, subty, &mut temp); - } - temp -} - -fn push_region_constraints<'tcx>(out: &mut Vec>, regions: Vec) { - for r in regions { - if !r.is_bound() { - out.push(Component::Region(r)); - } - } -} diff --git a/src/librustc/middle/ty/relate.rs b/src/librustc/middle/ty/relate.rs deleted file mode 100644 index d648c2c5884..00000000000 --- a/src/librustc/middle/ty/relate.rs +++ /dev/null @@ -1,684 +0,0 @@ -// Copyright 2012-2013 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Generalized type relating mechanism. A type relation R relates a -//! pair of values (A, B). A and B are usually types or regions but -//! can be other things. Examples of type relations are subtyping, -//! type equality, etc. - -use middle::def_id::DefId; -use middle::ty::subst::{ParamSpace, Substs}; -use middle::ty::{self, Ty, TyCtxt, TypeFoldable}; -use middle::ty::error::{ExpectedFound, TypeError}; -use std::rc::Rc; -use syntax::abi; -use rustc_front::hir as ast; - -pub type RelateResult<'tcx, T> = Result>; - -#[derive(Clone, Debug)] -pub enum Cause { - ExistentialRegionBound, // relating an existential region bound -} - -pub trait TypeRelation<'a,'tcx> : Sized { - fn tcx(&self) -> &'a TyCtxt<'tcx>; - - /// Returns a static string we can use for printouts. - fn tag(&self) -> &'static str; - - /// Returns true if the value `a` is the "expected" type in the - /// relation. Just affects error messages. - fn a_is_expected(&self) -> bool; - - fn with_cause(&mut self, _cause: Cause, f: F) -> R - where F: FnOnce(&mut Self) -> R - { - f(self) - } - - /// Generic relation routine suitable for most anything. - fn relate>(&mut self, a: &T, b: &T) -> RelateResult<'tcx, T> { - Relate::relate(self, a, b) - } - - /// Relete elements of two slices pairwise. - fn relate_zip>(&mut self, a: &[T], b: &[T]) -> RelateResult<'tcx, Vec> { - assert_eq!(a.len(), b.len()); - a.iter().zip(b).map(|(a, b)| self.relate(a, b)).collect() - } - - /// Switch variance for the purpose of relating `a` and `b`. - fn relate_with_variance>(&mut self, - variance: ty::Variance, - a: &T, - b: &T) - -> RelateResult<'tcx, T>; - - // Overrideable relations. You shouldn't typically call these - // directly, instead call `relate()`, which in turn calls - // these. This is both more uniform but also allows us to add - // additional hooks for other types in the future if needed - // without making older code, which called `relate`, obsolete. - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) - -> RelateResult<'tcx, Ty<'tcx>>; - - fn regions(&mut self, a: ty::Region, b: ty::Region) - -> RelateResult<'tcx, ty::Region>; - - fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) - -> RelateResult<'tcx, ty::Binder> - where T: Relate<'a,'tcx>; -} - -pub trait Relate<'a,'tcx>: TypeFoldable<'tcx> { - fn relate>(relation: &mut R, - a: &Self, - b: &Self) - -> RelateResult<'tcx, Self>; -} - -/////////////////////////////////////////////////////////////////////////// -// Relate impls - -impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::TypeAndMut<'tcx> { - fn relate(relation: &mut R, - a: &ty::TypeAndMut<'tcx>, - b: &ty::TypeAndMut<'tcx>) - -> RelateResult<'tcx, ty::TypeAndMut<'tcx>> - where R: TypeRelation<'a,'tcx> - { - debug!("{}.mts({:?}, {:?})", - relation.tag(), - a, - b); - if a.mutbl != b.mutbl { - Err(TypeError::Mutability) - } else { - let mutbl = a.mutbl; - let variance = match mutbl { - ast::Mutability::MutImmutable => ty::Covariant, - ast::Mutability::MutMutable => ty::Invariant, - }; - let ty = relation.relate_with_variance(variance, &a.ty, &b.ty)?; - Ok(ty::TypeAndMut {ty: ty, mutbl: mutbl}) - } - } -} - -// substitutions are not themselves relatable without more context, -// but they is an important subroutine for things that ARE relatable, -// like traits etc. -fn relate_item_substs<'a,'tcx:'a,R>(relation: &mut R, - item_def_id: DefId, - a_subst: &Substs<'tcx>, - b_subst: &Substs<'tcx>) - -> RelateResult<'tcx, Substs<'tcx>> - where R: TypeRelation<'a,'tcx> -{ - debug!("substs: item_def_id={:?} a_subst={:?} b_subst={:?}", - item_def_id, - a_subst, - b_subst); - - let variances; - let opt_variances = if relation.tcx().variance_computed.get() { - variances = relation.tcx().item_variances(item_def_id); - Some(&*variances) - } else { - None - }; - relate_substs(relation, opt_variances, a_subst, b_subst) -} - -pub fn relate_substs<'a,'tcx:'a,R>(relation: &mut R, - variances: Option<&ty::ItemVariances>, - a_subst: &Substs<'tcx>, - b_subst: &Substs<'tcx>) - -> RelateResult<'tcx, Substs<'tcx>> - where R: TypeRelation<'a,'tcx> -{ - let mut substs = Substs::empty(); - - for &space in &ParamSpace::all() { - let a_tps = a_subst.types.get_slice(space); - let b_tps = b_subst.types.get_slice(space); - let t_variances = variances.map(|v| v.types.get_slice(space)); - let tps = relate_type_params(relation, t_variances, a_tps, b_tps)?; - substs.types.replace(space, tps); - } - - for &space in &ParamSpace::all() { - let a_regions = a_subst.regions.get_slice(space); - let b_regions = b_subst.regions.get_slice(space); - let r_variances = variances.map(|v| v.regions.get_slice(space)); - let regions = relate_region_params(relation, - r_variances, - a_regions, - b_regions)?; - substs.regions.replace(space, regions); - } - - Ok(substs) -} - -fn relate_type_params<'a,'tcx:'a,R>(relation: &mut R, - variances: Option<&[ty::Variance]>, - a_tys: &[Ty<'tcx>], - b_tys: &[Ty<'tcx>]) - -> RelateResult<'tcx, Vec>> - where R: TypeRelation<'a,'tcx> -{ - if a_tys.len() != b_tys.len() { - return Err(TypeError::TyParamSize(expected_found(relation, - &a_tys.len(), - &b_tys.len()))); - } - - (0 .. a_tys.len()) - .map(|i| { - let a_ty = a_tys[i]; - let b_ty = b_tys[i]; - let v = variances.map_or(ty::Invariant, |v| v[i]); - relation.relate_with_variance(v, &a_ty, &b_ty) - }) - .collect() -} - -fn relate_region_params<'a,'tcx:'a,R>(relation: &mut R, - variances: Option<&[ty::Variance]>, - a_rs: &[ty::Region], - b_rs: &[ty::Region]) - -> RelateResult<'tcx, Vec> - where R: TypeRelation<'a,'tcx> -{ - let num_region_params = a_rs.len(); - - debug!("relate_region_params(a_rs={:?}, \ - b_rs={:?}, variances={:?})", - a_rs, - b_rs, - variances); - - assert_eq!(num_region_params, - variances.map_or(num_region_params, - |v| v.len())); - - assert_eq!(num_region_params, b_rs.len()); - - (0..a_rs.len()) - .map(|i| { - let a_r = a_rs[i]; - let b_r = b_rs[i]; - let variance = variances.map_or(ty::Invariant, |v| v[i]); - relation.relate_with_variance(variance, &a_r, &b_r) - }) - .collect() -} - -impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::BareFnTy<'tcx> { - fn relate(relation: &mut R, - a: &ty::BareFnTy<'tcx>, - b: &ty::BareFnTy<'tcx>) - -> RelateResult<'tcx, ty::BareFnTy<'tcx>> - where R: TypeRelation<'a,'tcx> - { - let unsafety = relation.relate(&a.unsafety, &b.unsafety)?; - let abi = relation.relate(&a.abi, &b.abi)?; - let sig = relation.relate(&a.sig, &b.sig)?; - Ok(ty::BareFnTy {unsafety: unsafety, - abi: abi, - sig: sig}) - } -} - -impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::FnSig<'tcx> { - fn relate(relation: &mut R, - a: &ty::FnSig<'tcx>, - b: &ty::FnSig<'tcx>) - -> RelateResult<'tcx, ty::FnSig<'tcx>> - where R: TypeRelation<'a,'tcx> - { - if a.variadic != b.variadic { - return Err(TypeError::VariadicMismatch( - expected_found(relation, &a.variadic, &b.variadic))); - } - - let inputs = relate_arg_vecs(relation, - &a.inputs, - &b.inputs)?; - - let output = match (a.output, b.output) { - (ty::FnConverging(a_ty), ty::FnConverging(b_ty)) => - Ok(ty::FnConverging(relation.relate(&a_ty, &b_ty)?)), - (ty::FnDiverging, ty::FnDiverging) => - Ok(ty::FnDiverging), - (a, b) => - Err(TypeError::ConvergenceMismatch( - expected_found(relation, &(a != ty::FnDiverging), &(b != ty::FnDiverging)))), - }?; - - return Ok(ty::FnSig {inputs: inputs, - output: output, - variadic: a.variadic}); - } -} - -fn relate_arg_vecs<'a,'tcx:'a,R>(relation: &mut R, - a_args: &[Ty<'tcx>], - b_args: &[Ty<'tcx>]) - -> RelateResult<'tcx, Vec>> - where R: TypeRelation<'a,'tcx> -{ - if a_args.len() != b_args.len() { - return Err(TypeError::ArgCount); - } - - a_args.iter().zip(b_args) - .map(|(a, b)| relation.relate_with_variance(ty::Contravariant, a, b)) - .collect() -} - -impl<'a,'tcx:'a> Relate<'a,'tcx> for ast::Unsafety { - fn relate(relation: &mut R, - a: &ast::Unsafety, - b: &ast::Unsafety) - -> RelateResult<'tcx, ast::Unsafety> - where R: TypeRelation<'a,'tcx> - { - if a != b { - Err(TypeError::UnsafetyMismatch(expected_found(relation, a, b))) - } else { - Ok(*a) - } - } -} - -impl<'a,'tcx:'a> Relate<'a,'tcx> for abi::Abi { - fn relate(relation: &mut R, - a: &abi::Abi, - b: &abi::Abi) - -> RelateResult<'tcx, abi::Abi> - where R: TypeRelation<'a,'tcx> - { - if a == b { - Ok(*a) - } else { - Err(TypeError::AbiMismatch(expected_found(relation, a, b))) - } - } -} - -impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ProjectionTy<'tcx> { - fn relate(relation: &mut R, - a: &ty::ProjectionTy<'tcx>, - b: &ty::ProjectionTy<'tcx>) - -> RelateResult<'tcx, ty::ProjectionTy<'tcx>> - where R: TypeRelation<'a,'tcx> - { - if a.item_name != b.item_name { - Err(TypeError::ProjectionNameMismatched( - expected_found(relation, &a.item_name, &b.item_name))) - } else { - let trait_ref = relation.relate(&a.trait_ref, &b.trait_ref)?; - Ok(ty::ProjectionTy { trait_ref: trait_ref, item_name: a.item_name }) - } - } -} - -impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ProjectionPredicate<'tcx> { - fn relate(relation: &mut R, - a: &ty::ProjectionPredicate<'tcx>, - b: &ty::ProjectionPredicate<'tcx>) - -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> - where R: TypeRelation<'a,'tcx> - { - let projection_ty = relation.relate(&a.projection_ty, &b.projection_ty)?; - let ty = relation.relate(&a.ty, &b.ty)?; - Ok(ty::ProjectionPredicate { projection_ty: projection_ty, ty: ty }) - } -} - -impl<'a,'tcx:'a> Relate<'a,'tcx> for Vec> { - fn relate(relation: &mut R, - a: &Vec>, - b: &Vec>) - -> RelateResult<'tcx, Vec>> - where R: TypeRelation<'a,'tcx> - { - // To be compatible, `a` and `b` must be for precisely the - // same set of traits and item names. We always require that - // projection bounds lists are sorted by trait-def-id and item-name, - // so we can just iterate through the lists pairwise, so long as they are the - // same length. - if a.len() != b.len() { - Err(TypeError::ProjectionBoundsLength(expected_found(relation, &a.len(), &b.len()))) - } else { - a.iter().zip(b) - .map(|(a, b)| relation.relate(a, b)) - .collect() - } - } -} - -impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ExistentialBounds<'tcx> { - fn relate(relation: &mut R, - a: &ty::ExistentialBounds<'tcx>, - b: &ty::ExistentialBounds<'tcx>) - -> RelateResult<'tcx, ty::ExistentialBounds<'tcx>> - where R: TypeRelation<'a,'tcx> - { - let r = - relation.with_cause( - Cause::ExistentialRegionBound, - |relation| relation.relate_with_variance(ty::Contravariant, - &a.region_bound, - &b.region_bound))?; - let nb = relation.relate(&a.builtin_bounds, &b.builtin_bounds)?; - let pb = relation.relate(&a.projection_bounds, &b.projection_bounds)?; - Ok(ty::ExistentialBounds { region_bound: r, - builtin_bounds: nb, - projection_bounds: pb }) - } -} - -impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::BuiltinBounds { - fn relate(relation: &mut R, - a: &ty::BuiltinBounds, - b: &ty::BuiltinBounds) - -> RelateResult<'tcx, ty::BuiltinBounds> - where R: TypeRelation<'a,'tcx> - { - // Two sets of builtin bounds are only relatable if they are - // precisely the same (but see the coercion code). - if a != b { - Err(TypeError::BuiltinBoundsMismatch(expected_found(relation, a, b))) - } else { - Ok(*a) - } - } -} - -impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::TraitRef<'tcx> { - fn relate(relation: &mut R, - a: &ty::TraitRef<'tcx>, - b: &ty::TraitRef<'tcx>) - -> RelateResult<'tcx, ty::TraitRef<'tcx>> - where R: TypeRelation<'a,'tcx> - { - // Different traits cannot be related - if a.def_id != b.def_id { - Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id))) - } else { - let substs = relate_item_substs(relation, a.def_id, a.substs, b.substs)?; - Ok(ty::TraitRef { def_id: a.def_id, substs: relation.tcx().mk_substs(substs) }) - } - } -} - -impl<'a,'tcx:'a> Relate<'a,'tcx> for Ty<'tcx> { - fn relate(relation: &mut R, - a: &Ty<'tcx>, - b: &Ty<'tcx>) - -> RelateResult<'tcx, Ty<'tcx>> - where R: TypeRelation<'a,'tcx> - { - relation.tys(a, b) - } -} - -/// The main "type relation" routine. Note that this does not handle -/// inference artifacts, so you should filter those out before calling -/// it. -pub fn super_relate_tys<'a,'tcx:'a,R>(relation: &mut R, - a: Ty<'tcx>, - b: Ty<'tcx>) - -> RelateResult<'tcx, Ty<'tcx>> - where R: TypeRelation<'a,'tcx> -{ - let tcx = relation.tcx(); - let a_sty = &a.sty; - let b_sty = &b.sty; - debug!("super_tys: a_sty={:?} b_sty={:?}", a_sty, b_sty); - match (a_sty, b_sty) { - (&ty::TyInfer(_), _) | - (_, &ty::TyInfer(_)) => - { - // The caller should handle these cases! - tcx.sess.bug("var types encountered in super_relate_tys") - } - - (&ty::TyError, _) | (_, &ty::TyError) => - { - Ok(tcx.types.err) - } - - (&ty::TyChar, _) | - (&ty::TyBool, _) | - (&ty::TyInt(_), _) | - (&ty::TyUint(_), _) | - (&ty::TyFloat(_), _) | - (&ty::TyStr, _) - if a == b => - { - Ok(a) - } - - (&ty::TyParam(ref a_p), &ty::TyParam(ref b_p)) - if a_p.idx == b_p.idx && a_p.space == b_p.space => - { - Ok(a) - } - - (&ty::TyEnum(a_def, a_substs), &ty::TyEnum(b_def, b_substs)) - if a_def == b_def => - { - let substs = relate_item_substs(relation, a_def.did, a_substs, b_substs)?; - Ok(tcx.mk_enum(a_def, tcx.mk_substs(substs))) - } - - (&ty::TyTrait(ref a_), &ty::TyTrait(ref b_)) => - { - let principal = relation.relate(&a_.principal, &b_.principal)?; - let bounds = relation.relate(&a_.bounds, &b_.bounds)?; - Ok(tcx.mk_trait(principal, bounds)) - } - - (&ty::TyStruct(a_def, a_substs), &ty::TyStruct(b_def, b_substs)) - if a_def == b_def => - { - let substs = relate_item_substs(relation, a_def.did, a_substs, b_substs)?; - Ok(tcx.mk_struct(a_def, tcx.mk_substs(substs))) - } - - (&ty::TyClosure(a_id, ref a_substs), - &ty::TyClosure(b_id, ref b_substs)) - if a_id == b_id => - { - // All TyClosure types with the same id represent - // the (anonymous) type of the same closure expression. So - // all of their regions should be equated. - let substs = relation.relate(a_substs, b_substs)?; - Ok(tcx.mk_closure_from_closure_substs(a_id, substs)) - } - - (&ty::TyBox(a_inner), &ty::TyBox(b_inner)) => - { - let typ = relation.relate(&a_inner, &b_inner)?; - Ok(tcx.mk_box(typ)) - } - - (&ty::TyRawPtr(ref a_mt), &ty::TyRawPtr(ref b_mt)) => - { - let mt = relation.relate(a_mt, b_mt)?; - Ok(tcx.mk_ptr(mt)) - } - - (&ty::TyRef(a_r, ref a_mt), &ty::TyRef(b_r, ref b_mt)) => - { - let r = relation.relate_with_variance(ty::Contravariant, a_r, b_r)?; - let mt = relation.relate(a_mt, b_mt)?; - Ok(tcx.mk_ref(tcx.mk_region(r), mt)) - } - - (&ty::TyArray(a_t, sz_a), &ty::TyArray(b_t, sz_b)) => - { - let t = relation.relate(&a_t, &b_t)?; - if sz_a == sz_b { - Ok(tcx.mk_array(t, sz_a)) - } else { - Err(TypeError::FixedArraySize(expected_found(relation, &sz_a, &sz_b))) - } - } - - (&ty::TySlice(a_t), &ty::TySlice(b_t)) => - { - let t = relation.relate(&a_t, &b_t)?; - Ok(tcx.mk_slice(t)) - } - - (&ty::TyTuple(ref as_), &ty::TyTuple(ref bs)) => - { - if as_.len() == bs.len() { - let ts = as_.iter().zip(bs) - .map(|(a, b)| relation.relate(a, b)) - .collect::>()?; - Ok(tcx.mk_tup(ts)) - } else if !(as_.is_empty() || bs.is_empty()) { - Err(TypeError::TupleSize( - expected_found(relation, &as_.len(), &bs.len()))) - } else { - Err(TypeError::Sorts(expected_found(relation, &a, &b))) - } - } - - (&ty::TyFnDef(a_def_id, a_substs, a_fty), - &ty::TyFnDef(b_def_id, b_substs, b_fty)) - if a_def_id == b_def_id => - { - let substs = relate_substs(relation, None, a_substs, b_substs)?; - let fty = relation.relate(a_fty, b_fty)?; - Ok(tcx.mk_fn_def(a_def_id, tcx.mk_substs(substs), fty)) - } - - (&ty::TyFnPtr(a_fty), &ty::TyFnPtr(b_fty)) => - { - let fty = relation.relate(a_fty, b_fty)?; - Ok(tcx.mk_fn_ptr(fty)) - } - - (&ty::TyProjection(ref a_data), &ty::TyProjection(ref b_data)) => - { - let projection_ty = relation.relate(a_data, b_data)?; - Ok(tcx.mk_projection(projection_ty.trait_ref, projection_ty.item_name)) - } - - _ => - { - Err(TypeError::Sorts(expected_found(relation, &a, &b))) - } - } -} - -impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ClosureSubsts<'tcx> { - fn relate(relation: &mut R, - a: &ty::ClosureSubsts<'tcx>, - b: &ty::ClosureSubsts<'tcx>) - -> RelateResult<'tcx, ty::ClosureSubsts<'tcx>> - where R: TypeRelation<'a,'tcx> - { - let func_substs = relate_substs(relation, None, a.func_substs, b.func_substs)?; - let upvar_tys = relation.relate_zip(&a.upvar_tys, &b.upvar_tys)?; - Ok(ty::ClosureSubsts { func_substs: relation.tcx().mk_substs(func_substs), - upvar_tys: upvar_tys }) - } -} - -impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::Region { - fn relate(relation: &mut R, - a: &ty::Region, - b: &ty::Region) - -> RelateResult<'tcx, ty::Region> - where R: TypeRelation<'a,'tcx> - { - relation.regions(*a, *b) - } -} - -impl<'a,'tcx:'a,T> Relate<'a,'tcx> for ty::Binder - where T: Relate<'a,'tcx> -{ - fn relate(relation: &mut R, - a: &ty::Binder, - b: &ty::Binder) - -> RelateResult<'tcx, ty::Binder> - where R: TypeRelation<'a,'tcx> - { - relation.binders(a, b) - } -} - -impl<'a,'tcx:'a,T> Relate<'a,'tcx> for Rc - where T: Relate<'a,'tcx> -{ - fn relate(relation: &mut R, - a: &Rc, - b: &Rc) - -> RelateResult<'tcx, Rc> - where R: TypeRelation<'a,'tcx> - { - let a: &T = a; - let b: &T = b; - Ok(Rc::new(relation.relate(a, b)?)) - } -} - -impl<'a,'tcx:'a,T> Relate<'a,'tcx> for Box - where T: Relate<'a,'tcx> -{ - fn relate(relation: &mut R, - a: &Box, - b: &Box) - -> RelateResult<'tcx, Box> - where R: TypeRelation<'a,'tcx> - { - let a: &T = a; - let b: &T = b; - Ok(Box::new(relation.relate(a, b)?)) - } -} - -/////////////////////////////////////////////////////////////////////////// -// Error handling - -pub fn expected_found<'a,'tcx:'a,R,T>(relation: &mut R, - a: &T, - b: &T) - -> ExpectedFound - where R: TypeRelation<'a,'tcx>, T: Clone -{ - expected_found_bool(relation.a_is_expected(), a, b) -} - -pub fn expected_found_bool(a_is_expected: bool, - a: &T, - b: &T) - -> ExpectedFound - where T: Clone -{ - let a = a.clone(); - let b = b.clone(); - if a_is_expected { - ExpectedFound {expected: a, found: b} - } else { - ExpectedFound {expected: b, found: a} - } -} diff --git a/src/librustc/middle/ty/structural_impls.rs b/src/librustc/middle/ty/structural_impls.rs deleted file mode 100644 index 23ec75b18e8..00000000000 --- a/src/librustc/middle/ty/structural_impls.rs +++ /dev/null @@ -1,815 +0,0 @@ -// Copyright 2012-2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use middle::ty::subst::{self, VecPerParamSpace}; -use middle::traits; -use middle::ty::{self, Lift, TraitRef, Ty, TyCtxt}; -use middle::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; - -use std::rc::Rc; -use syntax::abi; -use syntax::ptr::P; - -use rustc_front::hir; - -/////////////////////////////////////////////////////////////////////////// -// Lift implementations - -impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>> Lift<'tcx> for (A, B) { - type Lifted = (A::Lifted, B::Lifted); - fn lift_to_tcx(&self, tcx: &TyCtxt<'tcx>) -> Option { - tcx.lift(&self.0).and_then(|a| tcx.lift(&self.1).map(|b| (a, b))) - } -} - -impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for [T] { - type Lifted = Vec; - fn lift_to_tcx(&self, tcx: &TyCtxt<'tcx>) -> Option { - // type annotation needed to inform `projection_must_outlive` - let mut result : Vec<>::Lifted> - = Vec::with_capacity(self.len()); - for x in self { - if let Some(value) = tcx.lift(x) { - result.push(value); - } else { - return None; - } - } - Some(result) - } -} - -impl<'tcx> Lift<'tcx> for ty::Region { - type Lifted = Self; - fn lift_to_tcx(&self, _: &TyCtxt<'tcx>) -> Option { - Some(*self) - } -} - -impl<'a, 'tcx> Lift<'tcx> for TraitRef<'a> { - type Lifted = TraitRef<'tcx>; - fn lift_to_tcx(&self, tcx: &TyCtxt<'tcx>) -> Option> { - tcx.lift(&self.substs).map(|substs| TraitRef { - def_id: self.def_id, - substs: substs - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> { - type Lifted = ty::TraitPredicate<'tcx>; - fn lift_to_tcx(&self, tcx: &TyCtxt<'tcx>) -> Option> { - tcx.lift(&self.trait_ref).map(|trait_ref| ty::TraitPredicate { - trait_ref: trait_ref - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::EquatePredicate<'a> { - type Lifted = ty::EquatePredicate<'tcx>; - fn lift_to_tcx(&self, tcx: &TyCtxt<'tcx>) -> Option> { - tcx.lift(&(self.0, self.1)).map(|(a, b)| ty::EquatePredicate(a, b)) - } -} - -impl<'tcx, A: Copy+Lift<'tcx>, B: Copy+Lift<'tcx>> Lift<'tcx> for ty::OutlivesPredicate { - type Lifted = ty::OutlivesPredicate; - fn lift_to_tcx(&self, tcx: &TyCtxt<'tcx>) -> Option { - tcx.lift(&(self.0, self.1)).map(|(a, b)| ty::OutlivesPredicate(a, b)) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionPredicate<'a> { - type Lifted = ty::ProjectionPredicate<'tcx>; - fn lift_to_tcx(&self, tcx: &TyCtxt<'tcx>) -> Option> { - tcx.lift(&(self.projection_ty.trait_ref, self.ty)).map(|(trait_ref, ty)| { - ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy { - trait_ref: trait_ref, - item_name: self.projection_ty.item_name - }, - ty: ty - } - }) - } -} - -impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder { - type Lifted = ty::Binder; - fn lift_to_tcx(&self, tcx: &TyCtxt<'tcx>) -> Option { - tcx.lift(&self.0).map(|x| ty::Binder(x)) - } -} - -/////////////////////////////////////////////////////////////////////////// -// TypeFoldable implementations. -// -// Ideally, each type should invoke `folder.fold_foo(self)` and -// nothing else. In some cases, though, we haven't gotten around to -// adding methods on the `folder` yet, and thus the folding is -// hard-coded here. This is less-flexible, because folders cannot -// override the behavior, but there are a lot of random types and one -// can easily refactor the folding into the TypeFolder trait as -// needed. - -macro_rules! CopyImpls { - ($($ty:ty),+) => { - $( - impl<'tcx> TypeFoldable<'tcx> for $ty { - fn super_fold_with>(&self, _: &mut F) -> $ty { - *self - } - - fn super_visit_with>(&self, _: &mut F) -> bool { - false - } - } - )+ - } -} - -CopyImpls! { (), hir::Unsafety, abi::Abi } - -impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) { - fn super_fold_with>(&self, folder: &mut F) -> (T, U) { - (self.0.fold_with(folder), self.1.fold_with(folder)) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.0.visit_with(visitor) || self.1.visit_with(visitor) - } -} - -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Option { - fn super_fold_with>(&self, folder: &mut F) -> Self { - self.as_ref().map(|t| t.fold_with(folder)) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) - } -} - -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc { - fn super_fold_with>(&self, folder: &mut F) -> Self { - Rc::new((**self).fold_with(folder)) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - (**self).visit_with(visitor) - } -} - -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box { - fn super_fold_with>(&self, folder: &mut F) -> Self { - let content: T = (**self).fold_with(folder); - box content - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - (**self).visit_with(visitor) - } -} - -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec { - fn super_fold_with>(&self, folder: &mut F) -> Self { - self.iter().map(|t| t.fold_with(folder)).collect() - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) - } -} - -impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder { - fn super_fold_with>(&self, folder: &mut F) -> Self { - folder.enter_region_binder(); - let result = ty::Binder(self.0.fold_with(folder)); - folder.exit_region_binder(); - result - } - - fn fold_with>(&self, folder: &mut F) -> Self { - folder.fold_binder(self) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - visitor.enter_region_binder(); - if self.0.visit_with(visitor) { return true } - visitor.exit_region_binder(); - false - } -} - -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for P<[T]> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - self.iter().map(|t| t.fold_with(folder)).collect() - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) - } -} - -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for VecPerParamSpace { - fn super_fold_with>(&self, folder: &mut F) -> Self { - - // Things in the Fn space take place under an additional level - // of region binding relative to the other spaces. This is - // because those entries are attached to a method, and methods - // always introduce a level of region binding. - - let result = self.map_enumerated(|(space, index, elem)| { - if space == subst::FnSpace && index == 0 { - // enter new level when/if we reach the first thing in fn space - folder.enter_region_binder(); - } - elem.fold_with(folder) - }); - if result.len(subst::FnSpace) > 0 { - // if there was anything in fn space, exit the region binding level - folder.exit_region_binder(); - } - result - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - let mut entered_region_binder = false; - let result = self.iter_enumerated().any(|(space, index, t)| { - if space == subst::FnSpace && index == 0 { - visitor.enter_region_binder(); - entered_region_binder = true; - } - t.visit_with(visitor) - }); - if entered_region_binder { - visitor.exit_region_binder(); - } - result - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::TraitTy<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - ty::TraitTy { - principal: self.principal.fold_with(folder), - bounds: self.bounds.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.principal.visit_with(visitor) || self.bounds.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - let sty = match self.sty { - ty::TyBox(typ) => ty::TyBox(typ.fold_with(folder)), - ty::TyRawPtr(ref tm) => ty::TyRawPtr(tm.fold_with(folder)), - ty::TyArray(typ, sz) => ty::TyArray(typ.fold_with(folder), sz), - ty::TySlice(typ) => ty::TySlice(typ.fold_with(folder)), - ty::TyEnum(tid, ref substs) => { - let substs = substs.fold_with(folder); - ty::TyEnum(tid, folder.tcx().mk_substs(substs)) - } - ty::TyTrait(ref trait_ty) => ty::TyTrait(trait_ty.fold_with(folder)), - ty::TyTuple(ref ts) => ty::TyTuple(ts.fold_with(folder)), - ty::TyFnDef(def_id, substs, ref f) => { - let substs = substs.fold_with(folder); - let bfn = f.fold_with(folder); - ty::TyFnDef(def_id, - folder.tcx().mk_substs(substs), - folder.tcx().mk_bare_fn(bfn)) - } - ty::TyFnPtr(ref f) => { - let bfn = f.fold_with(folder); - ty::TyFnPtr(folder.tcx().mk_bare_fn(bfn)) - } - ty::TyRef(r, ref tm) => { - let r = r.fold_with(folder); - ty::TyRef(folder.tcx().mk_region(r), tm.fold_with(folder)) - } - ty::TyStruct(did, ref substs) => { - let substs = substs.fold_with(folder); - ty::TyStruct(did, folder.tcx().mk_substs(substs)) - } - ty::TyClosure(did, ref substs) => { - ty::TyClosure(did, substs.fold_with(folder)) - } - ty::TyProjection(ref data) => ty::TyProjection(data.fold_with(folder)), - ty::TyBool | ty::TyChar | ty::TyStr | ty::TyInt(_) | - ty::TyUint(_) | ty::TyFloat(_) | ty::TyError | ty::TyInfer(_) | - ty::TyParam(..) => self.sty.clone(), - }; - folder.tcx().mk_ty(sty) - } - - fn fold_with>(&self, folder: &mut F) -> Self { - folder.fold_ty(*self) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - match self.sty { - ty::TyBox(typ) => typ.visit_with(visitor), - ty::TyRawPtr(ref tm) => tm.visit_with(visitor), - ty::TyArray(typ, _sz) => typ.visit_with(visitor), - ty::TySlice(typ) => typ.visit_with(visitor), - ty::TyEnum(_tid, ref substs) => substs.visit_with(visitor), - ty::TyTrait(ref trait_ty) => trait_ty.visit_with(visitor), - ty::TyTuple(ref ts) => ts.visit_with(visitor), - ty::TyFnDef(_, substs, ref f) => { - substs.visit_with(visitor) || f.visit_with(visitor) - } - ty::TyFnPtr(ref f) => f.visit_with(visitor), - ty::TyRef(r, ref tm) => r.visit_with(visitor) || tm.visit_with(visitor), - ty::TyStruct(_did, ref substs) => substs.visit_with(visitor), - ty::TyClosure(_did, ref substs) => substs.visit_with(visitor), - ty::TyProjection(ref data) => data.visit_with(visitor), - ty::TyBool | ty::TyChar | ty::TyStr | ty::TyInt(_) | - ty::TyUint(_) | ty::TyFloat(_) | ty::TyError | ty::TyInfer(_) | - ty::TyParam(..) => false, - } - } - - fn visit_with>(&self, visitor: &mut V) -> bool { - visitor.visit_ty(self) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::BareFnTy<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - ty::BareFnTy { sig: self.sig.fold_with(folder), - abi: self.abi, - unsafety: self.unsafety } - } - - fn fold_with>(&self, folder: &mut F) -> Self { - folder.fold_bare_fn_ty(self) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.sig.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::ClosureTy<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - ty::ClosureTy { - sig: self.sig.fold_with(folder), - unsafety: self.unsafety, - abi: self.abi, - } - } - - fn fold_with>(&self, folder: &mut F) -> Self { - folder.fold_closure_ty(self) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.sig.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - ty::TypeAndMut { ty: self.ty.fold_with(folder), mutbl: self.mutbl } - } - - fn fold_with>(&self, folder: &mut F) -> Self { - folder.fold_mt(self) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.ty.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::FnOutput<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - match *self { - ty::FnConverging(ref ty) => ty::FnConverging(ty.fold_with(folder)), - ty::FnDiverging => ty::FnDiverging - } - } - - fn fold_with>(&self, folder: &mut F) -> Self { - folder.fold_output(self) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - match *self { - ty::FnConverging(ref ty) => ty.visit_with(visitor), - ty::FnDiverging => false, - } - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - ty::FnSig { inputs: self.inputs.fold_with(folder), - output: self.output.fold_with(folder), - variadic: self.variadic } - } - - fn fold_with>(&self, folder: &mut F) -> Self { - folder.fold_fn_sig(self) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.inputs.visit_with(visitor) || self.output.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::TraitRef<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - let substs = self.substs.fold_with(folder); - ty::TraitRef { - def_id: self.def_id, - substs: folder.tcx().mk_substs(substs), - } - } - - fn fold_with>(&self, folder: &mut F) -> Self { - folder.fold_trait_ref(self) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.substs.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::ImplHeader<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - ty::ImplHeader { - impl_def_id: self.impl_def_id, - self_ty: self.self_ty.fold_with(folder), - trait_ref: self.trait_ref.map(|t| t.fold_with(folder)), - predicates: self.predicates.iter().map(|p| p.fold_with(folder)).collect(), - } - } - - fn fold_with>(&self, folder: &mut F) -> Self { - folder.fold_impl_header(self) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.self_ty.visit_with(visitor) || - self.trait_ref.map(|r| r.visit_with(visitor)).unwrap_or(false) || - self.predicates.iter().any(|p| p.visit_with(visitor)) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::Region { - fn super_fold_with>(&self, _folder: &mut F) -> Self { - *self - } - - fn fold_with>(&self, folder: &mut F) -> Self { - folder.fold_region(*self) - } - - fn super_visit_with>(&self, _visitor: &mut V) -> bool { - false - } - - fn visit_with>(&self, visitor: &mut V) -> bool { - visitor.visit_region(*self) - } -} - -impl<'tcx> TypeFoldable<'tcx> for subst::Substs<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - subst::Substs { regions: self.regions.fold_with(folder), - types: self.types.fold_with(folder) } - } - - fn fold_with>(&self, folder: &mut F) -> Self { - folder.fold_substs(self) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.types.visit_with(visitor) || self.regions.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - let func_substs = self.func_substs.fold_with(folder); - ty::ClosureSubsts { - func_substs: folder.tcx().mk_substs(func_substs), - upvar_tys: self.upvar_tys.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.func_substs.visit_with(visitor) || self.upvar_tys.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::ItemSubsts<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - ty::ItemSubsts { - substs: self.substs.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.substs.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoRef<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - match *self { - ty::adjustment::AutoPtr(r, m) => { - let r = r.fold_with(folder); - ty::adjustment::AutoPtr(folder.tcx().mk_region(r), m) - } - ty::adjustment::AutoUnsafe(m) => ty::adjustment::AutoUnsafe(m) - } - } - - fn fold_with>(&self, folder: &mut F) -> Self { - folder.fold_autoref(self) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - match *self { - ty::adjustment::AutoPtr(r, _m) => r.visit_with(visitor), - ty::adjustment::AutoUnsafe(_m) => false, - } - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::BuiltinBounds { - fn super_fold_with>(&self, _folder: &mut F) -> Self { - *self - } - - fn super_visit_with>(&self, _visitor: &mut V) -> bool { - false - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialBounds<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - ty::ExistentialBounds { - region_bound: self.region_bound.fold_with(folder), - builtin_bounds: self.builtin_bounds, - projection_bounds: self.projection_bounds.fold_with(folder), - } - } - - fn fold_with>(&self, folder: &mut F) -> Self { - folder.fold_existential_bounds(self) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.region_bound.visit_with(visitor) || self.projection_bounds.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - ty::TypeParameterDef { - name: self.name, - def_id: self.def_id, - space: self.space, - index: self.index, - default: self.default.fold_with(folder), - default_def_id: self.default_def_id, - object_lifetime_default: self.object_lifetime_default.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.default.visit_with(visitor) || - self.object_lifetime_default.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::ObjectLifetimeDefault { - fn super_fold_with>(&self, folder: &mut F) -> Self { - match *self { - ty::ObjectLifetimeDefault::Ambiguous => - ty::ObjectLifetimeDefault::Ambiguous, - - ty::ObjectLifetimeDefault::BaseDefault => - ty::ObjectLifetimeDefault::BaseDefault, - - ty::ObjectLifetimeDefault::Specific(r) => - ty::ObjectLifetimeDefault::Specific(r.fold_with(folder)), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - match *self { - ty::ObjectLifetimeDefault::Specific(r) => r.visit_with(visitor), - _ => false, - } - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef { - fn super_fold_with>(&self, folder: &mut F) -> Self { - ty::RegionParameterDef { - name: self.name, - def_id: self.def_id, - space: self.space, - index: self.index, - bounds: self.bounds.fold_with(folder) - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.bounds.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::Generics<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - ty::Generics { - types: self.types.fold_with(folder), - regions: self.regions.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.types.visit_with(visitor) || self.regions.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::GenericPredicates<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - ty::GenericPredicates { - predicates: self.predicates.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.predicates.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - match *self { - ty::Predicate::Trait(ref a) => - ty::Predicate::Trait(a.fold_with(folder)), - ty::Predicate::Equate(ref binder) => - ty::Predicate::Equate(binder.fold_with(folder)), - ty::Predicate::RegionOutlives(ref binder) => - ty::Predicate::RegionOutlives(binder.fold_with(folder)), - ty::Predicate::TypeOutlives(ref binder) => - ty::Predicate::TypeOutlives(binder.fold_with(folder)), - ty::Predicate::Projection(ref binder) => - ty::Predicate::Projection(binder.fold_with(folder)), - ty::Predicate::WellFormed(data) => - ty::Predicate::WellFormed(data.fold_with(folder)), - ty::Predicate::ObjectSafe(trait_def_id) => - ty::Predicate::ObjectSafe(trait_def_id), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - match *self { - ty::Predicate::Trait(ref a) => a.visit_with(visitor), - ty::Predicate::Equate(ref binder) => binder.visit_with(visitor), - ty::Predicate::RegionOutlives(ref binder) => binder.visit_with(visitor), - ty::Predicate::TypeOutlives(ref binder) => binder.visit_with(visitor), - ty::Predicate::Projection(ref binder) => binder.visit_with(visitor), - ty::Predicate::WellFormed(data) => data.visit_with(visitor), - ty::Predicate::ObjectSafe(_trait_def_id) => false, - } - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionPredicate<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - ty::ProjectionPredicate { - projection_ty: self.projection_ty.fold_with(folder), - ty: self.ty.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.projection_ty.visit_with(visitor) || self.ty.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionTy<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - ty::ProjectionTy { - trait_ref: self.trait_ref.fold_with(folder), - item_name: self.item_name, - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.trait_ref.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::InstantiatedPredicates<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - ty::InstantiatedPredicates { - predicates: self.predicates.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.predicates.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - ty::EquatePredicate(self.0.fold_with(folder), - self.1.fold_with(folder)) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.0.visit_with(visitor) || self.1.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::TraitPredicate<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - ty::TraitPredicate { - trait_ref: self.trait_ref.fold_with(folder) - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.trait_ref.visit_with(visitor) - } -} - -impl<'tcx,T,U> TypeFoldable<'tcx> for ty::OutlivesPredicate - where T : TypeFoldable<'tcx>, - U : TypeFoldable<'tcx>, -{ - fn super_fold_with>(&self, folder: &mut F) -> Self { - ty::OutlivesPredicate(self.0.fold_with(folder), - self.1.fold_with(folder)) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.0.visit_with(visitor) || self.1.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::ClosureUpvar<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - ty::ClosureUpvar { - def: self.def, - span: self.span, - ty: self.ty.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.ty.visit_with(visitor) - } -} - -impl<'a, 'tcx> TypeFoldable<'tcx> for ty::ParameterEnvironment<'a, 'tcx> where 'tcx: 'a { - fn super_fold_with>(&self, folder: &mut F) -> Self { - ty::ParameterEnvironment { - tcx: self.tcx, - free_substs: self.free_substs.fold_with(folder), - implicit_region_bound: self.implicit_region_bound.fold_with(folder), - caller_bounds: self.caller_bounds.fold_with(folder), - selection_cache: traits::SelectionCache::new(), - evaluation_cache: traits::EvaluationCache::new(), - free_id_outlive: self.free_id_outlive, - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.free_substs.visit_with(visitor) || - self.implicit_region_bound.visit_with(visitor) || - self.caller_bounds.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::TypeScheme<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - ty::TypeScheme { - generics: self.generics.fold_with(folder), - ty: self.ty.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.generics.visit_with(visitor) || self.ty.visit_with(visitor) - } -} diff --git a/src/librustc/middle/ty/sty.rs b/src/librustc/middle/ty/sty.rs deleted file mode 100644 index d8f0dd29031..00000000000 --- a/src/librustc/middle/ty/sty.rs +++ /dev/null @@ -1,1240 +0,0 @@ -// Copyright 2012-2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! This module contains TypeVariants and its major components - -use middle::cstore; -use middle::def_id::DefId; -use middle::region; -use middle::ty::subst::{self, Substs}; -use middle::traits; -use middle::ty::{self, AdtDef, ToPredicate, TypeFlags, Ty, TyCtxt, TyS, TypeFoldable}; -use util::common::ErrorReported; - -use collections::enum_set::{self, EnumSet, CLike}; -use std::fmt; -use std::ops; -use std::mem; -use syntax::abi; -use syntax::ast::{self, Name}; -use syntax::parse::token::special_idents; - -use serialize::{Decodable, Decoder}; - -use rustc_front::hir; - -use self::FnOutput::*; -use self::InferTy::*; -use self::TypeVariants::*; - -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -pub struct TypeAndMut<'tcx> { - pub ty: Ty<'tcx>, - pub mutbl: hir::Mutability, -} - -#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, - RustcEncodable, RustcDecodable, Copy)] -/// A "free" region `fr` can be interpreted as "some region -/// at least as big as the scope `fr.scope`". -pub struct FreeRegion { - pub scope: region::CodeExtent, - pub bound_region: BoundRegion -} - -#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, - RustcEncodable, RustcDecodable, Copy)] -pub enum BoundRegion { - /// An anonymous region parameter for a given fn (&T) - BrAnon(u32), - - /// Named region parameters for functions (a in &'a T) - /// - /// The def-id is needed to distinguish free regions in - /// the event of shadowing. - BrNamed(DefId, Name), - - /// Fresh bound identifiers created during GLB computations. - BrFresh(u32), - - // Anonymous region for the implicit env pointer parameter - // to a closure - BrEnv -} - -// NB: If you change this, you'll probably want to change the corresponding -// AST structure in libsyntax/ast.rs as well. -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub enum TypeVariants<'tcx> { - /// The primitive boolean type. Written as `bool`. - TyBool, - - /// The primitive character type; holds a Unicode scalar value - /// (a non-surrogate code point). Written as `char`. - TyChar, - - /// A primitive signed integer type. For example, `i32`. - TyInt(ast::IntTy), - - /// A primitive unsigned integer type. For example, `u32`. - TyUint(ast::UintTy), - - /// A primitive floating-point type. For example, `f64`. - TyFloat(ast::FloatTy), - - /// An enumerated type, defined with `enum`. - /// - /// Substs here, possibly against intuition, *may* contain `TyParam`s. - /// That is, even after substitution it is possible that there are type - /// variables. This happens when the `TyEnum` corresponds to an enum - /// definition and not a concrete use of it. To get the correct `TyEnum` - /// from the tcx, use the `NodeId` from the `ast::Ty` and look it up in - /// the `ast_ty_to_ty_cache`. This is probably true for `TyStruct` as - /// well. - TyEnum(AdtDef<'tcx>, &'tcx Substs<'tcx>), - - /// A structure type, defined with `struct`. - /// - /// See warning about substitutions for enumerated types. - TyStruct(AdtDef<'tcx>, &'tcx Substs<'tcx>), - - /// `Box`; this is nominally a struct in the documentation, but is - /// special-cased internally. For example, it is possible to implicitly - /// move the contents of a box out of that box, and methods of any type - /// can have type `Box`. - TyBox(Ty<'tcx>), - - /// The pointee of a string slice. Written as `str`. - TyStr, - - /// An array with the given length. Written as `[T; n]`. - TyArray(Ty<'tcx>, usize), - - /// The pointee of an array slice. Written as `[T]`. - TySlice(Ty<'tcx>), - - /// A raw pointer. Written as `*mut T` or `*const T` - TyRawPtr(TypeAndMut<'tcx>), - - /// A reference; a pointer with an associated lifetime. Written as - /// `&a mut T` or `&'a T`. - TyRef(&'tcx Region, TypeAndMut<'tcx>), - - /// The anonymous type of a function declaration/definition. Each - /// function has a unique type. - TyFnDef(DefId, &'tcx Substs<'tcx>, &'tcx BareFnTy<'tcx>), - - /// A pointer to a function. Written as `fn() -> i32`. - /// FIXME: This is currently also used to represent the callee of a method; - /// see ty::MethodCallee etc. - TyFnPtr(&'tcx BareFnTy<'tcx>), - - /// A trait, defined with `trait`. - TyTrait(Box>), - - /// The anonymous type of a closure. Used to represent the type of - /// `|a| a`. - TyClosure(DefId, Box>), - - /// A tuple type. For example, `(i32, bool)`. - TyTuple(Vec>), - - /// The projection of an associated type. For example, - /// `>::N`. - TyProjection(ProjectionTy<'tcx>), - - /// A type parameter; for example, `T` in `fn f(x: T) {} - TyParam(ParamTy), - - /// A type variable used during type-checking. - TyInfer(InferTy), - - /// A placeholder for a type which could not be computed; this is - /// propagated to avoid useless error messages. - TyError, -} - -/// A closure can be modeled as a struct that looks like: -/// -/// struct Closure<'l0...'li, T0...Tj, U0...Uk> { -/// upvar0: U0, -/// ... -/// upvark: Uk -/// } -/// -/// where 'l0...'li and T0...Tj are the lifetime and type parameters -/// in scope on the function that defined the closure, and U0...Uk are -/// type parameters representing the types of its upvars (borrowed, if -/// appropriate). -/// -/// So, for example, given this function: -/// -/// fn foo<'a, T>(data: &'a mut T) { -/// do(|| data.count += 1) -/// } -/// -/// the type of the closure would be something like: -/// -/// struct Closure<'a, T, U0> { -/// data: U0 -/// } -/// -/// Note that the type of the upvar is not specified in the struct. -/// You may wonder how the impl would then be able to use the upvar, -/// if it doesn't know it's type? The answer is that the impl is -/// (conceptually) not fully generic over Closure but rather tied to -/// instances with the expected upvar types: -/// -/// impl<'b, 'a, T> FnMut() for Closure<'a, T, &'b mut &'a mut T> { -/// ... -/// } -/// -/// You can see that the *impl* fully specified the type of the upvar -/// and thus knows full well that `data` has type `&'b mut &'a mut T`. -/// (Here, I am assuming that `data` is mut-borrowed.) -/// -/// Now, the last question you may ask is: Why include the upvar types -/// as extra type parameters? The reason for this design is that the -/// upvar types can reference lifetimes that are internal to the -/// creating function. In my example above, for example, the lifetime -/// `'b` represents the extent of the closure itself; this is some -/// subset of `foo`, probably just the extent of the call to the to -/// `do()`. If we just had the lifetime/type parameters from the -/// enclosing function, we couldn't name this lifetime `'b`. Note that -/// there can also be lifetimes in the types of the upvars themselves, -/// if one of them happens to be a reference to something that the -/// creating fn owns. -/// -/// OK, you say, so why not create a more minimal set of parameters -/// that just includes the extra lifetime parameters? The answer is -/// primarily that it would be hard --- we don't know at the time when -/// we create the closure type what the full types of the upvars are, -/// nor do we know which are borrowed and which are not. In this -/// design, we can just supply a fresh type parameter and figure that -/// out later. -/// -/// All right, you say, but why include the type parameters from the -/// original function then? The answer is that trans may need them -/// when monomorphizing, and they may not appear in the upvars. A -/// closure could capture no variables but still make use of some -/// in-scope type parameter with a bound (e.g., if our example above -/// had an extra `U: Default`, and the closure called `U::default()`). -/// -/// There is another reason. This design (implicitly) prohibits -/// closures from capturing themselves (except via a trait -/// object). This simplifies closure inference considerably, since it -/// means that when we infer the kind of a closure or its upvars, we -/// don't have to handle cycles where the decisions we make for -/// closure C wind up influencing the decisions we ought to make for -/// closure C (which would then require fixed point iteration to -/// handle). Plus it fixes an ICE. :P -#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] -pub struct ClosureSubsts<'tcx> { - /// Lifetime and type parameters from the enclosing function. - /// These are separated out because trans wants to pass them around - /// when monomorphizing. - pub func_substs: &'tcx Substs<'tcx>, - - /// The types of the upvars. The list parallels the freevars and - /// `upvar_borrows` lists. These are kept distinct so that we can - /// easily index into them. - pub upvar_tys: Vec> -} - -impl<'tcx> Decodable for &'tcx ClosureSubsts<'tcx> { - fn decode(s: &mut S) -> Result<&'tcx ClosureSubsts<'tcx>, S::Error> { - let closure_substs = Decodable::decode(s)?; - let dummy_def_id: DefId = unsafe { mem::zeroed() }; - - cstore::tls::with_decoding_context(s, |dcx, _| { - // Intern the value - let ty = dcx.tcx().mk_closure_from_closure_substs(dummy_def_id, - Box::new(closure_substs)); - match ty.sty { - TyClosure(_, ref closure_substs) => Ok(&**closure_substs), - _ => unreachable!() - } - }) - } -} - -#[derive(Clone, PartialEq, Eq, Hash)] -pub struct TraitTy<'tcx> { - pub principal: ty::PolyTraitRef<'tcx>, - pub bounds: ExistentialBounds<'tcx>, -} - -impl<'tcx> TraitTy<'tcx> { - pub fn principal_def_id(&self) -> DefId { - self.principal.0.def_id - } - - /// Object types don't have a self-type specified. Therefore, when - /// we convert the principal trait-ref into a normal trait-ref, - /// you must give *some* self-type. A common choice is `mk_err()` - /// or some skolemized type. - pub fn principal_trait_ref_with_self_ty(&self, - tcx: &TyCtxt<'tcx>, - self_ty: Ty<'tcx>) - -> ty::PolyTraitRef<'tcx> - { - // otherwise the escaping regions would be captured by the binder - assert!(!self_ty.has_escaping_regions()); - - ty::Binder(TraitRef { - def_id: self.principal.0.def_id, - substs: tcx.mk_substs(self.principal.0.substs.with_self_ty(self_ty)), - }) - } - - pub fn projection_bounds_with_self_ty(&self, - tcx: &TyCtxt<'tcx>, - self_ty: Ty<'tcx>) - -> Vec> - { - // otherwise the escaping regions would be captured by the binders - assert!(!self_ty.has_escaping_regions()); - - self.bounds.projection_bounds.iter() - .map(|in_poly_projection_predicate| { - let in_projection_ty = &in_poly_projection_predicate.0.projection_ty; - let substs = tcx.mk_substs(in_projection_ty.trait_ref.substs.with_self_ty(self_ty)); - let trait_ref = ty::TraitRef::new(in_projection_ty.trait_ref.def_id, - substs); - let projection_ty = ty::ProjectionTy { - trait_ref: trait_ref, - item_name: in_projection_ty.item_name - }; - ty::Binder(ty::ProjectionPredicate { - projection_ty: projection_ty, - ty: in_poly_projection_predicate.0.ty - }) - }) - .collect() - } -} - -/// A complete reference to a trait. These take numerous guises in syntax, -/// but perhaps the most recognizable form is in a where clause: -/// -/// T : Foo -/// -/// This would be represented by a trait-reference where the def-id is the -/// def-id for the trait `Foo` and the substs defines `T` as parameter 0 in the -/// `SelfSpace` and `U` as parameter 0 in the `TypeSpace`. -/// -/// Trait references also appear in object types like `Foo`, but in -/// that case the `Self` parameter is absent from the substitutions. -/// -/// Note that a `TraitRef` introduces a level of region binding, to -/// account for higher-ranked trait bounds like `T : for<'a> Foo<&'a -/// U>` or higher-ranked object types. -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub struct TraitRef<'tcx> { - pub def_id: DefId, - pub substs: &'tcx Substs<'tcx>, -} - -pub type PolyTraitRef<'tcx> = Binder>; - -impl<'tcx> PolyTraitRef<'tcx> { - pub fn self_ty(&self) -> Ty<'tcx> { - self.0.self_ty() - } - - pub fn def_id(&self) -> DefId { - self.0.def_id - } - - pub fn substs(&self) -> &'tcx Substs<'tcx> { - // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<> - self.0.substs - } - - pub fn input_types(&self) -> &[Ty<'tcx>] { - // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<> - self.0.input_types() - } - - pub fn to_poly_trait_predicate(&self) -> ty::PolyTraitPredicate<'tcx> { - // Note that we preserve binding levels - Binder(ty::TraitPredicate { trait_ref: self.0.clone() }) - } -} - -/// Binder is a binder for higher-ranked lifetimes. It is part of the -/// compiler's representation for things like `for<'a> Fn(&'a isize)` -/// (which would be represented by the type `PolyTraitRef == -/// Binder`). Note that when we skolemize, instantiate, -/// erase, or otherwise "discharge" these bound regions, we change the -/// type from `Binder` to just `T` (see -/// e.g. `liberate_late_bound_regions`). -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct Binder(pub T); - -impl Binder { - /// Skips the binder and returns the "bound" value. This is a - /// risky thing to do because it's easy to get confused about - /// debruijn indices and the like. It is usually better to - /// discharge the binder using `no_late_bound_regions` or - /// `replace_late_bound_regions` or something like - /// that. `skip_binder` is only valid when you are either - /// extracting data that has nothing to do with bound regions, you - /// are doing some sort of test that does not involve bound - /// regions, or you are being very careful about your depth - /// accounting. - /// - /// Some examples where `skip_binder` is reasonable: - /// - extracting the def-id from a PolyTraitRef; - /// - comparing the self type of a PolyTraitRef to see if it is equal to - /// a type parameter `X`, since the type `X` does not reference any regions - pub fn skip_binder(&self) -> &T { - &self.0 - } - - pub fn as_ref(&self) -> Binder<&T> { - ty::Binder(&self.0) - } - - pub fn map_bound_ref(&self, f: F) -> Binder - where F: FnOnce(&T) -> U - { - self.as_ref().map_bound(f) - } - - pub fn map_bound(self, f: F) -> Binder - where F: FnOnce(T) -> U - { - ty::Binder(f(self.0)) - } -} - -impl fmt::Debug for TypeFlags { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.bits) - } -} - -/// Represents the projection of an associated type. In explicit UFCS -/// form this would be written `>::N`. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct ProjectionTy<'tcx> { - /// The trait reference `T as Trait<..>`. - pub trait_ref: ty::TraitRef<'tcx>, - - /// The name `N` of the associated type. - pub item_name: Name, -} - -impl<'tcx> ProjectionTy<'tcx> { - pub fn sort_key(&self) -> (DefId, Name) { - (self.trait_ref.def_id, self.item_name) - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub struct BareFnTy<'tcx> { - pub unsafety: hir::Unsafety, - pub abi: abi::Abi, - pub sig: PolyFnSig<'tcx>, -} - -#[derive(Clone, PartialEq, Eq, Hash)] -pub struct ClosureTy<'tcx> { - pub unsafety: hir::Unsafety, - pub abi: abi::Abi, - pub sig: PolyFnSig<'tcx>, -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] -pub enum FnOutput<'tcx> { - FnConverging(Ty<'tcx>), - FnDiverging -} - -impl<'tcx> FnOutput<'tcx> { - pub fn diverges(&self) -> bool { - *self == FnDiverging - } - - pub fn unwrap(self) -> Ty<'tcx> { - match self { - ty::FnConverging(t) => t, - ty::FnDiverging => unreachable!() - } - } - - pub fn unwrap_or(self, def: Ty<'tcx>) -> Ty<'tcx> { - match self { - ty::FnConverging(t) => t, - ty::FnDiverging => def - } - } -} - -pub type PolyFnOutput<'tcx> = Binder>; - -impl<'tcx> PolyFnOutput<'tcx> { - pub fn diverges(&self) -> bool { - self.0.diverges() - } -} - -/// Signature of a function type, which I have arbitrarily -/// decided to use to refer to the input/output types. -/// -/// - `inputs` is the list of arguments and their modes. -/// - `output` is the return type. -/// - `variadic` indicates whether this is a variadic function. (only true for foreign fns) -#[derive(Clone, PartialEq, Eq, Hash)] -pub struct FnSig<'tcx> { - pub inputs: Vec>, - pub output: FnOutput<'tcx>, - pub variadic: bool -} - -pub type PolyFnSig<'tcx> = Binder>; - -impl<'tcx> PolyFnSig<'tcx> { - pub fn inputs(&self) -> ty::Binder>> { - self.map_bound_ref(|fn_sig| fn_sig.inputs.clone()) - } - pub fn input(&self, index: usize) -> ty::Binder> { - self.map_bound_ref(|fn_sig| fn_sig.inputs[index]) - } - pub fn output(&self) -> ty::Binder> { - self.map_bound_ref(|fn_sig| fn_sig.output.clone()) - } - pub fn variadic(&self) -> bool { - self.skip_binder().variadic - } -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct ParamTy { - pub space: subst::ParamSpace, - pub idx: u32, - pub name: Name, -} - -impl ParamTy { - pub fn new(space: subst::ParamSpace, - index: u32, - name: Name) - -> ParamTy { - ParamTy { space: space, idx: index, name: name } - } - - pub fn for_self() -> ParamTy { - ParamTy::new(subst::SelfSpace, 0, special_idents::type_self.name) - } - - pub fn for_def(def: &ty::TypeParameterDef) -> ParamTy { - ParamTy::new(def.space, def.index, def.name) - } - - pub fn to_ty<'tcx>(self, tcx: &TyCtxt<'tcx>) -> Ty<'tcx> { - tcx.mk_param(self.space, self.idx, self.name) - } - - pub fn is_self(&self) -> bool { - self.space == subst::SelfSpace && self.idx == 0 - } -} - -/// A [De Bruijn index][dbi] is a standard means of representing -/// regions (and perhaps later types) in a higher-ranked setting. In -/// particular, imagine a type like this: -/// -/// for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char) -/// ^ ^ | | | -/// | | | | | -/// | +------------+ 1 | | -/// | | | -/// +--------------------------------+ 2 | -/// | | -/// +------------------------------------------+ 1 -/// -/// In this type, there are two binders (the outer fn and the inner -/// fn). We need to be able to determine, for any given region, which -/// fn type it is bound by, the inner or the outer one. There are -/// various ways you can do this, but a De Bruijn index is one of the -/// more convenient and has some nice properties. The basic idea is to -/// count the number of binders, inside out. Some examples should help -/// clarify what I mean. -/// -/// Let's start with the reference type `&'b isize` that is the first -/// argument to the inner function. This region `'b` is assigned a De -/// Bruijn index of 1, meaning "the innermost binder" (in this case, a -/// fn). The region `'a` that appears in the second argument type (`&'a -/// isize`) would then be assigned a De Bruijn index of 2, meaning "the -/// second-innermost binder". (These indices are written on the arrays -/// in the diagram). -/// -/// What is interesting is that De Bruijn index attached to a particular -/// variable will vary depending on where it appears. For example, -/// the final type `&'a char` also refers to the region `'a` declared on -/// the outermost fn. But this time, this reference is not nested within -/// any other binders (i.e., it is not an argument to the inner fn, but -/// rather the outer one). Therefore, in this case, it is assigned a -/// De Bruijn index of 1, because the innermost binder in that location -/// is the outer fn. -/// -/// [dbi]: http://en.wikipedia.org/wiki/De_Bruijn_index -#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug, Copy)] -pub struct DebruijnIndex { - // We maintain the invariant that this is never 0. So 1 indicates - // the innermost binder. To ensure this, create with `DebruijnIndex::new`. - pub depth: u32, -} - -/// Representation of regions. -/// -/// Unlike types, most region variants are "fictitious", not concrete, -/// regions. Among these, `ReStatic`, `ReEmpty` and `ReScope` are the only -/// ones representing concrete regions. -/// -/// ## Bound Regions -/// -/// These are regions that are stored behind a binder and must be substituted -/// with some concrete region before being used. There are 2 kind of -/// bound regions: early-bound, which are bound in a TypeScheme/TraitDef, -/// and are substituted by a Substs, and late-bound, which are part of -/// higher-ranked types (e.g. `for<'a> fn(&'a ())`) and are substituted by -/// the likes of `liberate_late_bound_regions`. The distinction exists -/// because higher-ranked lifetimes aren't supported in all places. See [1][2]. -/// -/// Unlike TyParam-s, bound regions are not supposed to exist "in the wild" -/// outside their binder, e.g. in types passed to type inference, and -/// should first be substituted (by skolemized regions, free regions, -/// or region variables). -/// -/// ## Skolemized and Free Regions -/// -/// One often wants to work with bound regions without knowing their precise -/// identity. For example, when checking a function, the lifetime of a borrow -/// can end up being assigned to some region parameter. In these cases, -/// it must be ensured that bounds on the region can't be accidentally -/// assumed without being checked. -/// -/// The process of doing that is called "skolemization". The bound regions -/// are replaced by skolemized markers, which don't satisfy any relation -/// not explicity provided. -/// -/// There are 2 kinds of skolemized regions in rustc: `ReFree` and -/// `ReSkolemized`. When checking an item's body, `ReFree` is supposed -/// to be used. These also support explicit bounds: both the internally-stored -/// *scope*, which the region is assumed to outlive, as well as other -/// relations stored in the `FreeRegionMap`. Note that these relations -/// aren't checked when you `make_subregion` (or `mk_eqty`), only by -/// `resolve_regions_and_report_errors`. -/// -/// When working with higher-ranked types, some region relations aren't -/// yet known, so you can't just call `resolve_regions_and_report_errors`. -/// `ReSkolemized` is designed for this purpose. In these contexts, -/// there's also the risk that some inference variable laying around will -/// get unified with your skolemized region: if you want to check whether -/// `for<'a> Foo<'_>: 'a`, and you substitute your bound region `'a` -/// with a skolemized region `'%a`, the variable `'_` would just be -/// instantiated to the skolemized region `'%a`, which is wrong because -/// the inference variable is supposed to satisfy the relation -/// *for every value of the skolemized region*. To ensure that doesn't -/// happen, you can use `leak_check`. This is more clearly explained -/// by infer/higher_ranked/README.md. -/// -/// [1] http://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/ -/// [2] http://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/ -#[derive(Clone, PartialEq, Eq, Hash, Copy, RustcEncodable, RustcDecodable)] -pub enum Region { - // Region bound in a type or fn declaration which will be - // substituted 'early' -- that is, at the same time when type - // parameters are substituted. - ReEarlyBound(EarlyBoundRegion), - - // Region bound in a function scope, which will be substituted when the - // function is called. - ReLateBound(DebruijnIndex, BoundRegion), - - /// When checking a function body, the types of all arguments and so forth - /// that refer to bound region parameters are modified to refer to free - /// region parameters. - ReFree(FreeRegion), - - /// A concrete region naming some statically determined extent - /// (e.g. an expression or sequence of statements) within the - /// current function. - ReScope(region::CodeExtent), - - /// Static data that has an "infinite" lifetime. Top in the region lattice. - ReStatic, - - /// A region variable. Should not exist after typeck. - ReVar(RegionVid), - - /// A skolemized region - basically the higher-ranked version of ReFree. - /// Should not exist after typeck. - ReSkolemized(SkolemizedRegionVid, BoundRegion), - - /// Empty lifetime is for data that is never accessed. - /// Bottom in the region lattice. We treat ReEmpty somewhat - /// specially; at least right now, we do not generate instances of - /// it during the GLB computations, but rather - /// generate an error instead. This is to improve error messages. - /// The only way to get an instance of ReEmpty is to have a region - /// variable with no constraints. - ReEmpty, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)] -pub struct EarlyBoundRegion { - pub space: subst::ParamSpace, - pub index: u32, - pub name: Name, -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct TyVid { - pub index: u32 -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct IntVid { - pub index: u32 -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct FloatVid { - pub index: u32 -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)] -pub struct RegionVid { - pub index: u32 -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] -pub struct SkolemizedRegionVid { - pub index: u32 -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub enum InferTy { - TyVar(TyVid), - IntVar(IntVid), - FloatVar(FloatVid), - - /// A `FreshTy` is one that is generated as a replacement for an - /// unbound type variable. This is convenient for caching etc. See - /// `middle::infer::freshen` for more details. - FreshTy(u32), - FreshIntTy(u32), - FreshFloatTy(u32) -} - -/// Bounds suitable for an existentially quantified type parameter -/// such as those that appear in object types or closure types. -#[derive(PartialEq, Eq, Hash, Clone)] -pub struct ExistentialBounds<'tcx> { - pub region_bound: ty::Region, - pub builtin_bounds: BuiltinBounds, - pub projection_bounds: Vec>, -} - -impl<'tcx> ExistentialBounds<'tcx> { - pub fn new(region_bound: ty::Region, - builtin_bounds: BuiltinBounds, - projection_bounds: Vec>) - -> Self { - let mut projection_bounds = projection_bounds; - projection_bounds.sort_by(|a, b| a.sort_key().cmp(&b.sort_key())); - ExistentialBounds { - region_bound: region_bound, - builtin_bounds: builtin_bounds, - projection_bounds: projection_bounds - } - } -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -pub struct BuiltinBounds(EnumSet); - -impl BuiltinBounds { - pub fn empty() -> BuiltinBounds { - BuiltinBounds(EnumSet::new()) - } - - pub fn iter(&self) -> enum_set::Iter { - self.into_iter() - } - - pub fn to_predicates<'tcx>(&self, - tcx: &TyCtxt<'tcx>, - self_ty: Ty<'tcx>) -> Vec> { - self.iter().filter_map(|builtin_bound| - match traits::trait_ref_for_builtin_bound(tcx, builtin_bound, self_ty) { - Ok(trait_ref) => Some(trait_ref.to_predicate()), - Err(ErrorReported) => { None } - } - ).collect() - } -} - -impl ops::Deref for BuiltinBounds { - type Target = EnumSet; - fn deref(&self) -> &Self::Target { &self.0 } -} - -impl ops::DerefMut for BuiltinBounds { - fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } -} - -impl<'a> IntoIterator for &'a BuiltinBounds { - type Item = BuiltinBound; - type IntoIter = enum_set::Iter; - fn into_iter(self) -> Self::IntoIter { - (**self).into_iter() - } -} - -#[derive(Clone, RustcEncodable, PartialEq, Eq, RustcDecodable, Hash, - Debug, Copy)] -#[repr(usize)] -pub enum BuiltinBound { - Send, - Sized, - Copy, - Sync, -} - -impl CLike for BuiltinBound { - fn to_usize(&self) -> usize { - *self as usize - } - fn from_usize(v: usize) -> BuiltinBound { - unsafe { mem::transmute(v) } - } -} - -impl<'tcx> TyCtxt<'tcx> { - pub fn try_add_builtin_trait(&self, - trait_def_id: DefId, - builtin_bounds: &mut EnumSet) - -> bool - { - //! Checks whether `trait_ref` refers to one of the builtin - //! traits, like `Send`, and adds the corresponding - //! bound to the set `builtin_bounds` if so. Returns true if `trait_ref` - //! is a builtin trait. - - match self.lang_items.to_builtin_kind(trait_def_id) { - Some(bound) => { builtin_bounds.insert(bound); true } - None => false - } - } -} - -impl DebruijnIndex { - pub fn new(depth: u32) -> DebruijnIndex { - assert!(depth > 0); - DebruijnIndex { depth: depth } - } - - pub fn shifted(&self, amount: u32) -> DebruijnIndex { - DebruijnIndex { depth: self.depth + amount } - } -} - -// Region utilities -impl Region { - pub fn is_bound(&self) -> bool { - match *self { - ty::ReEarlyBound(..) => true, - ty::ReLateBound(..) => true, - _ => false - } - } - - pub fn needs_infer(&self) -> bool { - match *self { - ty::ReVar(..) | ty::ReSkolemized(..) => true, - _ => false - } - } - - pub fn escapes_depth(&self, depth: u32) -> bool { - match *self { - ty::ReLateBound(debruijn, _) => debruijn.depth > depth, - _ => false, - } - } - - /// Returns the depth of `self` from the (1-based) binding level `depth` - pub fn from_depth(&self, depth: u32) -> Region { - match *self { - ty::ReLateBound(debruijn, r) => ty::ReLateBound(DebruijnIndex { - depth: debruijn.depth - (depth - 1) - }, r), - r => r - } - } -} - -// Type utilities -impl<'tcx> TyS<'tcx> { - pub fn as_opt_param_ty(&self) -> Option { - match self.sty { - ty::TyParam(ref d) => Some(d.clone()), - _ => None, - } - } - - pub fn is_nil(&self) -> bool { - match self.sty { - TyTuple(ref tys) => tys.is_empty(), - _ => false - } - } - - pub fn is_empty(&self, _cx: &TyCtxt) -> bool { - // FIXME(#24885): be smarter here - match self.sty { - TyEnum(def, _) | TyStruct(def, _) => def.is_empty(), - _ => false - } - } - - pub fn is_primitive(&self) -> bool { - match self.sty { - TyBool | TyChar | TyInt(_) | TyUint(_) | TyFloat(_) => true, - _ => false, - } - } - - pub fn is_ty_var(&self) -> bool { - match self.sty { - TyInfer(TyVar(_)) => true, - _ => false - } - } - - pub fn is_phantom_data(&self) -> bool { - if let TyStruct(def, _) = self.sty { - def.is_phantom_data() - } else { - false - } - } - - pub fn is_bool(&self) -> bool { self.sty == TyBool } - - pub fn is_param(&self, space: subst::ParamSpace, index: u32) -> bool { - match self.sty { - ty::TyParam(ref data) => data.space == space && data.idx == index, - _ => false, - } - } - - pub fn is_self(&self) -> bool { - match self.sty { - TyParam(ref p) => p.space == subst::SelfSpace, - _ => false - } - } - - pub fn is_slice(&self) -> bool { - match self.sty { - TyRawPtr(mt) | TyRef(_, mt) => match mt.ty.sty { - TySlice(_) | TyStr => true, - _ => false, - }, - _ => false - } - } - - pub fn is_structural(&self) -> bool { - match self.sty { - TyStruct(..) | TyTuple(_) | TyEnum(..) | - TyArray(..) | TyClosure(..) => true, - _ => self.is_slice() | self.is_trait() - } - } - - #[inline] - pub fn is_simd(&self) -> bool { - match self.sty { - TyStruct(def, _) => def.is_simd(), - _ => false - } - } - - pub fn sequence_element_type(&self, cx: &TyCtxt<'tcx>) -> Ty<'tcx> { - match self.sty { - TyArray(ty, _) | TySlice(ty) => ty, - TyStr => cx.mk_mach_uint(ast::UintTy::U8), - _ => cx.sess.bug(&format!("sequence_element_type called on non-sequence value: {}", - self)), - } - } - - pub fn simd_type(&self, cx: &TyCtxt<'tcx>) -> Ty<'tcx> { - match self.sty { - TyStruct(def, substs) => { - def.struct_variant().fields[0].ty(cx, substs) - } - _ => panic!("simd_type called on invalid type") - } - } - - pub fn simd_size(&self, _cx: &TyCtxt) -> usize { - match self.sty { - TyStruct(def, _) => def.struct_variant().fields.len(), - _ => panic!("simd_size called on invalid type") - } - } - - pub fn is_region_ptr(&self) -> bool { - match self.sty { - TyRef(..) => true, - _ => false - } - } - - pub fn is_unsafe_ptr(&self) -> bool { - match self.sty { - TyRawPtr(_) => return true, - _ => return false - } - } - - pub fn is_unique(&self) -> bool { - match self.sty { - TyBox(_) => true, - _ => false - } - } - - /* - A scalar type is one that denotes an atomic datum, with no sub-components. - (A TyRawPtr is scalar because it represents a non-managed pointer, so its - contents are abstract to rustc.) - */ - pub fn is_scalar(&self) -> bool { - match self.sty { - TyBool | TyChar | TyInt(_) | TyFloat(_) | TyUint(_) | - TyInfer(IntVar(_)) | TyInfer(FloatVar(_)) | - TyFnDef(..) | TyFnPtr(_) | TyRawPtr(_) => true, - _ => false - } - } - - /// Returns true if this type is a floating point type and false otherwise. - pub fn is_floating_point(&self) -> bool { - match self.sty { - TyFloat(_) | - TyInfer(FloatVar(_)) => true, - _ => false, - } - } - - pub fn is_trait(&self) -> bool { - match self.sty { - TyTrait(..) => true, - _ => false - } - } - - pub fn is_integral(&self) -> bool { - match self.sty { - TyInfer(IntVar(_)) | TyInt(_) | TyUint(_) => true, - _ => false - } - } - - pub fn is_fresh(&self) -> bool { - match self.sty { - TyInfer(FreshTy(_)) => true, - TyInfer(FreshIntTy(_)) => true, - TyInfer(FreshFloatTy(_)) => true, - _ => false - } - } - - pub fn is_uint(&self) -> bool { - match self.sty { - TyInfer(IntVar(_)) | TyUint(ast::UintTy::Us) => true, - _ => false - } - } - - pub fn is_char(&self) -> bool { - match self.sty { - TyChar => true, - _ => false - } - } - - pub fn is_fp(&self) -> bool { - match self.sty { - TyInfer(FloatVar(_)) | TyFloat(_) => true, - _ => false - } - } - - pub fn is_numeric(&self) -> bool { - self.is_integral() || self.is_fp() - } - - pub fn is_signed(&self) -> bool { - match self.sty { - TyInt(_) => true, - _ => false - } - } - - pub fn is_machine(&self) -> bool { - match self.sty { - TyInt(ast::IntTy::Is) | TyUint(ast::UintTy::Us) => false, - TyInt(..) | TyUint(..) | TyFloat(..) => true, - _ => false - } - } - - pub fn has_concrete_skeleton(&self) -> bool { - match self.sty { - TyParam(_) | TyInfer(_) | TyError => false, - _ => true, - } - } - - // Returns the type and mutability of *ty. - // - // The parameter `explicit` indicates if this is an *explicit* dereference. - // Some types---notably unsafe ptrs---can only be dereferenced explicitly. - pub fn builtin_deref(&self, explicit: bool, pref: ty::LvaluePreference) - -> Option> - { - match self.sty { - TyBox(ty) => { - Some(TypeAndMut { - ty: ty, - mutbl: if pref == ty::PreferMutLvalue { - hir::MutMutable - } else { - hir::MutImmutable - }, - }) - }, - TyRef(_, mt) => Some(mt), - TyRawPtr(mt) if explicit => Some(mt), - _ => None - } - } - - // Returns the type of ty[i] - pub fn builtin_index(&self) -> Option> { - match self.sty { - TyArray(ty, _) | TySlice(ty) => Some(ty), - _ => None - } - } - - pub fn fn_sig(&self) -> &'tcx PolyFnSig<'tcx> { - match self.sty { - TyFnDef(_, _, ref f) | TyFnPtr(ref f) => &f.sig, - _ => panic!("Ty::fn_sig() called on non-fn type: {:?}", self) - } - } - - /// Returns the ABI of the given function. - pub fn fn_abi(&self) -> abi::Abi { - match self.sty { - TyFnDef(_, _, ref f) | TyFnPtr(ref f) => f.abi, - _ => panic!("Ty::fn_abi() called on non-fn type"), - } - } - - // Type accessors for substructures of types - pub fn fn_args(&self) -> ty::Binder>> { - self.fn_sig().inputs() - } - - pub fn fn_ret(&self) -> Binder> { - self.fn_sig().output() - } - - pub fn is_fn(&self) -> bool { - match self.sty { - TyFnDef(..) | TyFnPtr(_) => true, - _ => false - } - } - - pub fn ty_to_def_id(&self) -> Option { - match self.sty { - TyTrait(ref tt) => Some(tt.principal_def_id()), - TyStruct(def, _) | - TyEnum(def, _) => Some(def.did), - TyClosure(id, _) => Some(id), - _ => None - } - } - - pub fn ty_adt_def(&self) -> Option> { - match self.sty { - TyStruct(adt, _) | TyEnum(adt, _) => Some(adt), - _ => None - } - } - - /// Returns the regions directly referenced from this type (but - /// not types reachable from this type via `walk_tys`). This - /// ignores late-bound regions binders. - pub fn regions(&self) -> Vec { - match self.sty { - TyRef(region, _) => { - vec![*region] - } - TyTrait(ref obj) => { - let mut v = vec![obj.bounds.region_bound]; - v.extend_from_slice(obj.principal.skip_binder() - .substs.regions.as_slice()); - v - } - TyEnum(_, substs) | - TyStruct(_, substs) => { - substs.regions.as_slice().to_vec() - } - TyClosure(_, ref substs) => { - substs.func_substs.regions.as_slice().to_vec() - } - TyProjection(ref data) => { - data.trait_ref.substs.regions.as_slice().to_vec() - } - TyFnDef(..) | - TyFnPtr(_) | - TyBool | - TyChar | - TyInt(_) | - TyUint(_) | - TyFloat(_) | - TyBox(_) | - TyStr | - TyArray(_, _) | - TySlice(_) | - TyRawPtr(_) | - TyTuple(_) | - TyParam(_) | - TyInfer(_) | - TyError => { - vec![] - } - } - } -} diff --git a/src/librustc/middle/ty/subst.rs b/src/librustc/middle/ty/subst.rs deleted file mode 100644 index b9bf550704e..00000000000 --- a/src/librustc/middle/ty/subst.rs +++ /dev/null @@ -1,737 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Type substitutions. - -pub use self::ParamSpace::*; - -use middle::cstore; -use middle::def_id::DefId; -use middle::ty::{self, Ty, TyCtxt}; -use middle::ty::fold::{TypeFoldable, TypeFolder}; - -use serialize::{Encodable, Encoder, Decodable, Decoder}; -use std::fmt; -use std::iter::IntoIterator; -use std::slice::Iter; -use std::vec::{Vec, IntoIter}; -use syntax::codemap::{Span, DUMMY_SP}; - -/////////////////////////////////////////////////////////////////////////// - -/// A substitution mapping type/region parameters to new values. We -/// identify each in-scope parameter by an *index* and a *parameter -/// space* (which indices where the parameter is defined; see -/// `ParamSpace`). -#[derive(Clone, PartialEq, Eq, Hash)] -pub struct Substs<'tcx> { - pub types: VecPerParamSpace>, - pub regions: VecPerParamSpace, -} - -impl<'tcx> Substs<'tcx> { - pub fn new(t: VecPerParamSpace>, - r: VecPerParamSpace) - -> Substs<'tcx> - { - Substs { types: t, regions: r } - } - - pub fn new_type(t: Vec>, - r: Vec) - -> Substs<'tcx> - { - Substs::new(VecPerParamSpace::new(t, Vec::new(), Vec::new()), - VecPerParamSpace::new(r, Vec::new(), Vec::new())) - } - - pub fn new_trait(t: Vec>, - r: Vec, - s: Ty<'tcx>) - -> Substs<'tcx> - { - Substs::new(VecPerParamSpace::new(t, vec!(s), Vec::new()), - VecPerParamSpace::new(r, Vec::new(), Vec::new())) - } - - pub fn empty() -> Substs<'tcx> { - Substs { - types: VecPerParamSpace::empty(), - regions: VecPerParamSpace::empty(), - } - } - - pub fn is_noop(&self) -> bool { - self.regions.is_empty() && self.types.is_empty() - } - - pub fn type_for_def(&self, ty_param_def: &ty::TypeParameterDef) -> Ty<'tcx> { - *self.types.get(ty_param_def.space, ty_param_def.index as usize) - } - - pub fn self_ty(&self) -> Option> { - self.types.get_self().cloned() - } - - pub fn with_self_ty(&self, self_ty: Ty<'tcx>) -> Substs<'tcx> { - assert!(self.self_ty().is_none()); - let mut s = (*self).clone(); - s.types.push(SelfSpace, self_ty); - s - } - - pub fn erase_regions(self) -> Substs<'tcx> { - let Substs { types, regions } = self; - let regions = regions.map(|_| ty::ReStatic); - Substs { types: types, regions: regions } - } - - pub fn with_method(self, - m_types: Vec>, - m_regions: Vec) - -> Substs<'tcx> - { - let Substs { types, regions } = self; - let types = types.with_slice(FnSpace, &m_types); - let regions = regions.with_slice(FnSpace, &m_regions); - Substs { types: types, regions: regions } - } - - pub fn with_method_from(&self, - meth_substs: &Substs<'tcx>) - -> Substs<'tcx> - { - let Substs { types, regions } = self.clone(); - let types = types.with_slice(FnSpace, meth_substs.types.get_slice(FnSpace)); - let regions = regions.with_slice(FnSpace, meth_substs.regions.get_slice(FnSpace)); - Substs { types: types, regions: regions } - } - - pub fn with_method_from_subst(self, other: &Substs<'tcx>) -> Substs<'tcx> { - let Substs { types, regions } = self; - let types = types.with_slice(FnSpace, other.types.get_slice(FnSpace)); - let regions = regions.with_slice(FnSpace, other.regions.get_slice(FnSpace)); - Substs { types: types, regions: regions } - } - - /// Creates a trait-ref out of this substs, ignoring the FnSpace substs - pub fn to_trait_ref(&self, tcx: &TyCtxt<'tcx>, trait_id: DefId) - -> ty::TraitRef<'tcx> { - let Substs { mut types, mut regions } = self.clone(); - types.truncate(FnSpace, 0); - regions.truncate(FnSpace, 0); - - ty::TraitRef { - def_id: trait_id, - substs: tcx.mk_substs(Substs { types: types, regions: regions }) - } - } -} - -impl<'tcx> Encodable for Substs<'tcx> { - - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - cstore::tls::with_encoding_context(s, |ecx, rbml_w| { - ecx.encode_substs(rbml_w, self); - Ok(()) - }) - } -} - -impl<'tcx> Decodable for Substs<'tcx> { - fn decode(d: &mut D) -> Result, D::Error> { - cstore::tls::with_decoding_context(d, |dcx, rbml_r| { - Ok(dcx.decode_substs(rbml_r)) - }) - } -} - -impl<'tcx> Decodable for &'tcx Substs<'tcx> { - fn decode(d: &mut D) -> Result<&'tcx Substs<'tcx>, D::Error> { - let substs = cstore::tls::with_decoding_context(d, |dcx, rbml_r| { - let substs = dcx.decode_substs(rbml_r); - dcx.tcx().mk_substs(substs) - }); - - Ok(substs) - } -} - -/////////////////////////////////////////////////////////////////////////// -// ParamSpace - -#[derive(PartialOrd, Ord, PartialEq, Eq, Copy, - Clone, Hash, RustcEncodable, RustcDecodable, Debug)] -pub enum ParamSpace { - TypeSpace, // Type parameters attached to a type definition, trait, or impl - SelfSpace, // Self parameter on a trait - FnSpace, // Type parameters attached to a method or fn -} - -impl ParamSpace { - pub fn all() -> [ParamSpace; 3] { - [TypeSpace, SelfSpace, FnSpace] - } - - pub fn to_uint(self) -> usize { - match self { - TypeSpace => 0, - SelfSpace => 1, - FnSpace => 2, - } - } - - pub fn from_uint(u: usize) -> ParamSpace { - match u { - 0 => TypeSpace, - 1 => SelfSpace, - 2 => FnSpace, - _ => panic!("Invalid ParamSpace: {}", u) - } - } -} - -/// Vector of things sorted by param space. Used to keep -/// the set of things declared on the type, self, or method -/// distinct. -#[derive(PartialEq, Eq, Clone, Hash, RustcEncodable, RustcDecodable)] -pub struct VecPerParamSpace { - // This was originally represented as a tuple with one Vec for - // each variant of ParamSpace, and that remains the abstraction - // that it provides to its clients. - // - // Here is how the representation corresponds to the abstraction - // i.e. the "abstraction function" AF: - // - // AF(self) = (self.content[..self.type_limit], - // self.content[self.type_limit..self.self_limit], - // self.content[self.self_limit..]) - type_limit: usize, - self_limit: usize, - content: Vec, -} - -/// The `split` function converts one `VecPerParamSpace` into this -/// `SeparateVecsPerParamSpace` structure. -pub struct SeparateVecsPerParamSpace { - pub types: Vec, - pub selfs: Vec, - pub fns: Vec, -} - -impl fmt::Debug for VecPerParamSpace { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "[{:?};{:?};{:?}]", - self.get_slice(TypeSpace), - self.get_slice(SelfSpace), - self.get_slice(FnSpace)) - } -} - -impl VecPerParamSpace { - fn limits(&self, space: ParamSpace) -> (usize, usize) { - match space { - TypeSpace => (0, self.type_limit), - SelfSpace => (self.type_limit, self.self_limit), - FnSpace => (self.self_limit, self.content.len()), - } - } - - pub fn empty() -> VecPerParamSpace { - VecPerParamSpace { - type_limit: 0, - self_limit: 0, - content: Vec::new() - } - } - - /// `t` is the type space. - /// `s` is the self space. - /// `f` is the fn space. - pub fn new(t: Vec, s: Vec, f: Vec) -> VecPerParamSpace { - let type_limit = t.len(); - let self_limit = type_limit + s.len(); - - let mut content = t; - content.extend(s); - content.extend(f); - - VecPerParamSpace { - type_limit: type_limit, - self_limit: self_limit, - content: content, - } - } - - fn new_internal(content: Vec, type_limit: usize, self_limit: usize) - -> VecPerParamSpace - { - VecPerParamSpace { - type_limit: type_limit, - self_limit: self_limit, - content: content, - } - } - - /// Appends `value` to the vector associated with `space`. - /// - /// Unlike the `push` method in `Vec`, this should not be assumed - /// to be a cheap operation (even when amortized over many calls). - pub fn push(&mut self, space: ParamSpace, value: T) { - let (_, limit) = self.limits(space); - match space { - TypeSpace => { self.type_limit += 1; self.self_limit += 1; } - SelfSpace => { self.self_limit += 1; } - FnSpace => { } - } - self.content.insert(limit, value); - } - - /// Appends `values` to the vector associated with `space`. - /// - /// Unlike the `extend` method in `Vec`, this should not be assumed - /// to be a cheap operation (even when amortized over many calls). - pub fn extend>(&mut self, space: ParamSpace, values: I) { - // This could be made more efficient, obviously. - for item in values { - self.push(space, item); - } - } - - pub fn pop(&mut self, space: ParamSpace) -> Option { - let (start, limit) = self.limits(space); - if start == limit { - None - } else { - match space { - TypeSpace => { self.type_limit -= 1; self.self_limit -= 1; } - SelfSpace => { self.self_limit -= 1; } - FnSpace => {} - } - if self.content.is_empty() { - None - } else { - Some(self.content.remove(limit - 1)) - } - } - } - - pub fn truncate(&mut self, space: ParamSpace, len: usize) { - // FIXME (#15435): slow; O(n^2); could enhance vec to make it O(n). - while self.len(space) > len { - self.pop(space); - } - } - - pub fn replace(&mut self, space: ParamSpace, elems: Vec) { - // FIXME (#15435): slow; O(n^2); could enhance vec to make it O(n). - self.truncate(space, 0); - for t in elems { - self.push(space, t); - } - } - - pub fn get_self<'a>(&'a self) -> Option<&'a T> { - let v = self.get_slice(SelfSpace); - assert!(v.len() <= 1); - if v.is_empty() { None } else { Some(&v[0]) } - } - - pub fn len(&self, space: ParamSpace) -> usize { - self.get_slice(space).len() - } - - pub fn is_empty_in(&self, space: ParamSpace) -> bool { - self.len(space) == 0 - } - - pub fn get_slice<'a>(&'a self, space: ParamSpace) -> &'a [T] { - let (start, limit) = self.limits(space); - &self.content[start.. limit] - } - - pub fn get_mut_slice<'a>(&'a mut self, space: ParamSpace) -> &'a mut [T] { - let (start, limit) = self.limits(space); - &mut self.content[start.. limit] - } - - pub fn opt_get<'a>(&'a self, - space: ParamSpace, - index: usize) - -> Option<&'a T> { - let v = self.get_slice(space); - if index < v.len() { Some(&v[index]) } else { None } - } - - pub fn get<'a>(&'a self, space: ParamSpace, index: usize) -> &'a T { - &self.get_slice(space)[index] - } - - pub fn iter<'a>(&'a self) -> Iter<'a,T> { - self.content.iter() - } - - pub fn into_iter(self) -> IntoIter { - self.content.into_iter() - } - - pub fn iter_enumerated<'a>(&'a self) -> EnumeratedItems<'a,T> { - EnumeratedItems::new(self) - } - - pub fn as_slice(&self) -> &[T] { - &self.content - } - - pub fn into_vec(self) -> Vec { - self.content - } - - pub fn all_vecs