Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] rustc_typeck: check well-formedness of type aliases. #54033

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions src/Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "chalk-engine"
version = "0.7.0"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
Expand Down Expand Up @@ -643,6 +643,14 @@ dependencies = [
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "ena"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "env_logger"
version = "0.5.12"
Expand Down Expand Up @@ -1856,7 +1864,7 @@ dependencies = [
"backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"chalk-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"chalk-engine 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"flate2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"fmt_macros 0.0.0",
"graphviz 0.0.0",
Expand Down Expand Up @@ -2122,7 +2130,7 @@ name = "rustc_data_structures"
version = "0.0.0"
dependencies = [
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"ena 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ena 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
Expand Down Expand Up @@ -2383,7 +2391,7 @@ name = "rustc_traits"
version = "0.0.0"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"chalk-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"chalk-engine 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"graphviz 0.0.0",
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
Expand Down Expand Up @@ -3126,7 +3134,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum cargo_metadata 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d6809b327f87369e6f3651efd2c5a96c49847a3ed2559477ecba79014751ee1"
"checksum cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "4a6007c146fdd28d4512a794b07ffe9d8e89e6bf86e2e0c4ddff2e1fb54a0007"
"checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3"
"checksum chalk-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "25ce2f28f55ed544a2a3756b7acf41dd7d6f27acffb2086439950925506af7d0"
"checksum chalk-engine 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "217042da49c0c0655bbc4aa9f9bed20c7a599429faddc9b2ef3bd09a2769d3ef"
"checksum chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "295635afd6853aa9f20baeb7f0204862440c0fe994c5a253d5f479dac41d047e"
"checksum chrono 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6962c635d530328acc53ac6a955e83093fedc91c5809dfac1fa60fa470830a37"
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
Expand Down Expand Up @@ -3156,6 +3164,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
"checksum elasticlunr-rs 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4837d77a1e157489a3933b743fd774ae75074e0e390b2b7f071530048a0d87ee"
"checksum ena 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "25b4e5febb25f08c49f1b07dc33a182729a6b21edfb562b5aef95f78e0dbe5bb"
"checksum ena 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dc8393b3c7352f94092497f6b52019643e493b6b890eb417cdb7c46117e621"
"checksum env_logger 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)" = "f4d7e69c283751083d53d01eac767407343b8b69c4bd70058e08adc2637cb257"
"checksum environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4b14e20978669064c33b4c1e0fb4083412e40fe56cbea2eae80fd7591503ee"
Expand Down
5 changes: 5 additions & 0 deletions src/bootstrap/bin/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,11 @@ fn main() {
{
cmd.arg("-Dwarnings");
cmd.arg("-Dbare_trait_objects");
if !(stage == "0" || target.is_none() && version.is_none()) {
// HACK(eddyb) allow bootstrapping while we're testing with
// the lint on `deny` by default. Remove before merging.
cmd.arg("-Atype_alias_missing_bounds");
}
}

if verbose > 1 {
Expand Down
6 changes: 4 additions & 2 deletions src/libgraphviz/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -574,8 +574,10 @@ impl<'a> LabelText<'a> {
}
}

pub type Nodes<'a,N> = Cow<'a,[N]>;
pub type Edges<'a,E> = Cow<'a,[E]>;
#[allow(type_alias_bounds)]
pub type Nodes<'a,N: Clone> = Cow<'a,[N]>;
#[allow(type_alias_bounds)]
pub type Edges<'a,E: Clone> = Cow<'a,[E]>;

// (The type parameters in GraphWalk should be associated items,
// when/if Rust supports such.)
Expand Down
8 changes: 5 additions & 3 deletions src/librustc/infer/canonical/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,12 @@ pub struct QueryResult<'tcx, R> {
pub value: R,
}

pub type Canonicalized<'gcx, V> = Canonical<'gcx, <V as Lift<'gcx>>::Lifted>;
#[allow(type_alias_bounds)]
pub type Canonicalized<'gcx, V: Lift<'gcx>> = Canonical<'gcx, V::Lifted>;

pub type CanonicalizedQueryResult<'gcx, T> =
Lrc<Canonical<'gcx, QueryResult<'gcx, <T as Lift<'gcx>>::Lifted>>>;
#[allow(type_alias_bounds)]
pub type CanonicalizedQueryResult<'gcx, T: Lift<'gcx>> =
Lrc<Canonical<'gcx, QueryResult<'gcx, T::Lifted>>>;

/// Indicates whether or not we were able to prove the query to be
/// true.
Expand Down
168 changes: 85 additions & 83 deletions src/librustc/infer/error_reporting/need_type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,71 +8,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use hir::{self, Local, Pat, Body, HirId};
use hir::intravisit::{self, Visitor, NestedVisitorMap};
use hir::{self, HirId};
use infer::InferCtxt;
use infer::type_variable::TypeVariableOrigin;
use traits;
use ty::{self, Ty, Infer, TyVar};
use syntax::source_map::CompilerDesugaringKind;
use syntax_pos::Span;
use errors::DiagnosticBuilder;

struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
target_ty: &'a Ty<'tcx>,
hir_map: &'a hir::map::Map<'gcx>,
found_local_pattern: Option<&'gcx Pat>,
found_arg_pattern: Option<&'gcx Pat>,
}

impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
fn node_matches_type(&mut self, node_id: HirId) -> bool {
let ty_opt = self.infcx.in_progress_tables.and_then(|tables| {
tables.borrow().node_id_to_type_opt(node_id)
});
match ty_opt {
Some(ty) => {
let ty = self.infcx.resolve_type_vars_if_possible(&ty);
ty.walk().any(|inner_ty| {
inner_ty == *self.target_ty || match (&inner_ty.sty, &self.target_ty.sty) {
(&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => {
self.infcx
.type_variables
.borrow_mut()
.sub_unified(a_vid, b_vid)
}
_ => false,
}
})
}
None => false,
}
}
}

impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
NestedVisitorMap::OnlyBodies(&self.hir_map)
}

fn visit_local(&mut self, local: &'gcx Local) {
if self.found_local_pattern.is_none() && self.node_matches_type(local.hir_id) {
self.found_local_pattern = Some(&*local.pat);
}
intravisit::walk_local(self, local);
}

fn visit_body(&mut self, body: &'gcx Body) {
for argument in &body.arguments {
if self.found_arg_pattern.is_none() && self.node_matches_type(argument.hir_id) {
self.found_arg_pattern = Some(&*argument.pat);
}
}
intravisit::walk_body(self, body);
}
}


impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
pub fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String {
if let ty::Infer(ty::TyVar(ty_vid)) = (*ty).sty {
Expand All @@ -89,38 +32,85 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}

pub fn need_type_info_err(&self,
body_id: Option<hir::BodyId>,
span: Span,
ty: Ty<'tcx>)
-> DiagnosticBuilder<'gcx> {
cause: &traits::ObligationCause<'tcx>,
ty: Ty<'tcx>)
-> DiagnosticBuilder<'gcx> {
let ty = self.resolve_type_vars_if_possible(&ty);
let name = self.extract_type_name(&ty);

let mut err_span = span;
let mut labels = vec![(
span,
cause.span,
if &name == "_" {
"cannot infer type".to_string()
} else {
format!("cannot infer type for `{}`", name)
},
)];
let mut span = cause.span;

let mut local_visitor = FindLocalByTypeVisitor {
infcx: &self,
target_ty: &ty,
hir_map: &self.tcx.hir,
found_local_pattern: None,
found_arg_pattern: None,
};

if let Some(body_id) = body_id {
let expr = self.tcx.hir.expect_expr(body_id.node_id);
local_visitor.visit_expr(expr);
// NB. Lower values are more preferred.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
enum LocalKind {
ClosureArg,
Let,
}

if let Some(pattern) = local_visitor.found_arg_pattern {
err_span = pattern.span;
let found_local = self.in_progress_tables.and_then(|tables| {
let tables = tables.borrow();
let local_id_root = tables.local_id_root?;
assert!(local_id_root.is_local());

tables.node_types().iter().filter_map(|(&local_id, &node_ty)| {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

such ECS.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: It'd be nice to pull this out into some sort of helper function, I think? I'd also like to see a comment, something like:


Iterate over the all the things that we've assigned types to. Check whether they represent local variables and, if so, if the type of that local variable references the type we are looking for.

let node_id = self.tcx.hir.hir_to_node_id(HirId {
owner: local_id_root.index,
local_id,
});

let (kind, pattern) = match self.tcx.hir.find(node_id) {
Some(hir::Node::Local(local)) => {
(LocalKind::Let, &*local.pat)
}

Some(hir::Node::Binding(pat)) |
Some(hir::Node::Pat(pat)) => {
let parent_id = self.tcx.hir.get_parent_node(node_id);
match self.tcx.hir.find(parent_id) {
Some(hir::Node::Expr(e)) => {
match e.node {
hir::ExprKind::Closure(..) => {}
_ => return None,
}
}
_ => return None,
}

(LocalKind::ClosureArg, pat)
}

_ => return None
};

let node_ty = self.resolve_type_vars_if_possible(&node_ty);
let matches_type = node_ty.walk().any(|inner_ty| {
inner_ty == ty || match (&inner_ty.sty, &ty.sty) {
(&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => {
self.type_variables
.borrow_mut()
.sub_unified(a_vid, b_vid)
}
_ => false,
}
});
if !matches_type {
return None;
}

Some((kind, pattern))
}).min_by_key(|&(kind, pattern)| (kind, pattern.hir_id.local_id))
});

if let Some((LocalKind::ClosureArg, pattern)) = found_local {
span = pattern.span;
// We don't want to show the default label for closures.
//
// So, before clearing, the output would look something like this:
Expand All @@ -139,7 +129,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
labels.clear();
labels.push(
(pattern.span, "consider giving this closure parameter a type".to_string()));
} else if let Some(pattern) = local_visitor.found_local_pattern {
} else if let Some((LocalKind::Let, pattern)) = found_local {
if let Some(simple_ident) = pattern.simple_ident() {
match pattern.span.compiler_desugaring_kind() {
None => labels.push((pattern.span,
Expand All @@ -155,10 +145,22 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
}

let mut err = struct_span_err!(self.tcx.sess,
err_span,
E0282,
"type annotations needed");
let lint = self.get_lint_from_cause_code(&cause.code);
macro_rules! struct_span_err_or_lint {
($code:ident, $($message:tt)*) => {
match lint {
Some((lint, id)) => {
let message = format!($($message)*);
self.tcx.struct_span_lint_node(lint, id, span, &message)
}
None => {
struct_span_err!(self.tcx.sess, span, $code, $($message)*)
}
}
}
}

let mut err = struct_span_err_or_lint!(E0282, "type annotations needed");

for (target_span, label_message) in labels {
err.span_label(target_span, label_message);
Expand Down
4 changes: 1 addition & 3 deletions src/librustc/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1424,8 +1424,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
/// new obligations that must further be processed.
pub fn partially_normalize_associated_types_in<T>(
&self,
span: Span,
body_id: ast::NodeId,
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
value: &T,
) -> InferOk<'tcx, T>
Expand All @@ -1434,7 +1433,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
{
debug!("partially_normalize_associated_types_in(value={:?})", value);
let mut selcx = traits::SelectionContext::new(self);
let cause = ObligationCause::misc(span, body_id);
let traits::Normalized { value, obligations } =
traits::normalize(&mut selcx, param_env, cause, value);
debug!(
Expand Down
10 changes: 3 additions & 7 deletions src/librustc/infer/outlives/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,9 @@

use infer::{GenericKind, InferCtxt};
use infer::outlives::free_region_map::FreeRegionMap;
use traits::query::outlives_bounds::{self, OutlivesBound};
use traits::{self, query::outlives_bounds::{self, OutlivesBound}};
use ty::{self, Ty};

use syntax::ast;
use syntax_pos::Span;

/// The `OutlivesEnvironment` collects information about what outlives
/// what in a given type-checking setting. For example, if we have a
/// where-clause like `where T: 'a` in scope, then the
Expand Down Expand Up @@ -136,15 +133,14 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
&mut self,
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
fn_sig_tys: &[Ty<'tcx>],
body_id: ast::NodeId,
span: Span,
cause: &traits::ObligationCause<'tcx>,
) {
debug!("add_implied_bounds()");

for &ty in fn_sig_tys {
let ty = infcx.resolve_type_vars_if_possible(&ty);
debug!("add_implied_bounds: ty = {}", ty);
let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span);
let implied_bounds = infcx.implied_outlives_bounds(self.param_env, cause, ty);
self.add_outlives_bounds(Some(infcx), implied_bounds)
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/librustc/lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,12 @@ declare_lint! {
cannot be referred to by absolute paths"
}

declare_lint! {
pub TYPE_ALIAS_MISSING_BOUNDS,
Deny,
"type aliases missing bounds required by the type being aliased, are now deprecated"
}

/// Some lints that are buffered from `libsyntax`. See `syntax::early_buffered_lints`.
pub mod parser {
declare_lint! {
Expand Down Expand Up @@ -406,6 +412,7 @@ impl LintPass for HardwiredLints {
PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
MACRO_USE_EXTERN_CRATE,
MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
TYPE_ALIAS_MISSING_BOUNDS,
parser::QUESTION_MARK_MACRO_SEP,
)
}
Expand Down
Loading