rustc_hir_typeck: fix paths and partially mv files

This commit is contained in:
lcnr 2022-10-20 17:51:37 +02:00
parent f468a90bad
commit fb3ab13a1c
39 changed files with 1232 additions and 1133 deletions

View file

@ -3568,6 +3568,32 @@ dependencies = [
"rustc_target",
]
[[package]]
name = "rustc_hir_typeck"
version = "0.1.0"
dependencies = [
"rustc_ast",
"rustc_data_structures",
"rustc_errors",
"rustc_graphviz",
"rustc_hir",
"rustc_hir_analysis",
"rustc_hir_pretty",
"rustc_index",
"rustc_infer",
"rustc_lint",
"rustc_macros",
"rustc_middle",
"rustc_serialize",
"rustc_session",
"rustc_span",
"rustc_target",
"rustc_trait_selection",
"rustc_type_ir",
"smallvec",
"tracing",
]
[[package]]
name = "rustc_incremental"
version = "0.0.0"
@ -3637,6 +3663,7 @@ dependencies = [
"rustc_expand",
"rustc_hir",
"rustc_hir_analysis",
"rustc_hir_typeck",
"rustc_incremental",
"rustc_lint",
"rustc_macros",

View file

@ -582,7 +582,7 @@ fn create_assoc_bindings_for_generic_args<'a>(
assoc_bindings
}
pub(crate) fn create_substs_for_associated_item(
pub fn create_substs_for_associated_item(
&self,
span: Span,
item_def_id: DefId,

View file

@ -1,6 +1,5 @@
use crate::check::intrinsicck::InlineAsmCtxt;
use super::coercion::CoerceMany;
use super::compare_method::check_type_bounds;
use super::compare_method::{compare_impl_method, compare_ty_impl};
use super::*;
@ -10,10 +9,8 @@
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{ItemKind, Node, PathSegment};
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt};
use rustc_infer::traits::Obligation;
use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
@ -34,7 +31,7 @@
use std::ops::ControlFlow;
pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
match tcx.sess.target.is_abi_supported(abi) {
Some(true) => (),
Some(false) => {
@ -69,313 +66,6 @@ pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ab
}
}
/// Helper used for fns and closures. Does the grungy work of checking a function
/// body and returns the function context used for that purpose, since in the case of a fn item
/// there is still a bit more to do.
///
/// * ...
/// * inherited: other fields inherited from the enclosing fn (if any)
#[instrument(skip(inherited, body), level = "debug")]
pub(super) fn check_fn<'a, 'tcx>(
inherited: &'a Inherited<'tcx>,
param_env: ty::ParamEnv<'tcx>,
fn_sig: ty::FnSig<'tcx>,
decl: &'tcx hir::FnDecl<'tcx>,
fn_id: hir::HirId,
body: &'tcx hir::Body<'tcx>,
can_be_generator: Option<hir::Movability>,
return_type_pre_known: bool,
) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
// Create the function context. This is either derived from scratch or,
// in the case of closures, based on the outer context.
let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
fcx.ps.set(UnsafetyState::function(fn_sig.unsafety, fn_id));
fcx.return_type_pre_known = return_type_pre_known;
let tcx = fcx.tcx;
let hir = tcx.hir();
let declared_ret_ty = fn_sig.output();
let ret_ty =
fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars(
declared_ret_ty,
body.value.hir_id,
decl.output.span(),
param_env,
));
// If we replaced declared_ret_ty with infer vars, then we must be inferring
// an opaque type, so set a flag so we can improve diagnostics.
fcx.return_type_has_opaque = ret_ty != declared_ret_ty;
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
let span = body.value.span;
fn_maybe_err(tcx, span, fn_sig.abi);
if fn_sig.abi == Abi::RustCall {
let expected_args = if let ImplicitSelfKind::None = decl.implicit_self { 1 } else { 2 };
let err = || {
let item = match tcx.hir().get(fn_id) {
Node::Item(hir::Item { kind: ItemKind::Fn(header, ..), .. }) => Some(header),
Node::ImplItem(hir::ImplItem {
kind: hir::ImplItemKind::Fn(header, ..), ..
}) => Some(header),
Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Fn(header, ..),
..
}) => Some(header),
// Closures are RustCall, but they tuple their arguments, so shouldn't be checked
Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => None,
node => bug!("Item being checked wasn't a function/closure: {:?}", node),
};
if let Some(header) = item {
tcx.sess.span_err(header.span, "functions with the \"rust-call\" ABI must take a single non-self argument that is a tuple");
}
};
if fn_sig.inputs().len() != expected_args {
err()
} else {
// FIXME(CraftSpider) Add a check on parameter expansion, so we don't just make the ICE happen later on
// This will probably require wide-scale changes to support a TupleKind obligation
// We can't resolve this without knowing the type of the param
if !matches!(fn_sig.inputs()[expected_args - 1].kind(), ty::Tuple(_) | ty::Param(_)) {
err()
}
}
}
if body.generator_kind.is_some() && can_be_generator.is_some() {
let yield_ty = fcx
.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
// Resume type defaults to `()` if the generator has no argument.
let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit());
fcx.resume_yield_tys = Some((resume_ty, yield_ty));
}
GatherLocalsVisitor::new(&fcx).visit_body(body);
// C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
// (as it's created inside the body itself, not passed in from outside).
let maybe_va_list = if fn_sig.c_variadic {
let span = body.params.last().unwrap().span;
let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span));
let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span));
Some(tcx.bound_type_of(va_list_did).subst(tcx, &[region.into()]))
} else {
None
};
// Add formal parameters.
let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs);
let inputs_fn = fn_sig.inputs().iter().copied();
for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
// Check the pattern.
let ty_span = try { inputs_hir?.get(idx)?.span };
fcx.check_pat_top(&param.pat, param_ty, ty_span, false);
// Check that argument is Sized.
// The check for a non-trivial pattern is a hack to avoid duplicate warnings
// for simple cases like `fn foo(x: Trait)`,
// where we would error once on the parameter as a whole, and once on the binding `x`.
if param.pat.simple_ident().is_none() && !tcx.features().unsized_fn_params {
fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
}
fcx.write_ty(param.hir_id, param_ty);
}
inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
fcx.in_tail_expr = true;
if let ty::Dynamic(..) = declared_ret_ty.kind() {
// FIXME: We need to verify that the return type is `Sized` after the return expression has
// been evaluated so that we have types available for all the nodes being returned, but that
// requires the coerced evaluated type to be stored. Moving `check_return_expr` before this
// causes unsized errors caused by the `declared_ret_ty` to point at the return expression,
// while keeping the current ordering we will ignore the tail expression's type because we
// don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr`
// because we will trigger "unreachable expression" lints unconditionally.
// Because of all of this, we perform a crude check to know whether the simplest `!Sized`
// case that a newcomer might make, returning a bare trait, and in that case we populate
// the tail expression's type so that the suggestion will be correct, but ignore all other
// possible cases.
fcx.check_expr(&body.value);
fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
} else {
fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
fcx.check_return_expr(&body.value, false);
}
fcx.in_tail_expr = false;
// We insert the deferred_generator_interiors entry after visiting the body.
// This ensures that all nested generators appear before the entry of this generator.
// resolve_generator_interiors relies on this property.
let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) {
let interior = fcx
.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span });
fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind));
let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap();
Some(GeneratorTypes {
resume_ty,
yield_ty,
interior,
movability: can_be_generator.unwrap(),
})
} else {
None
};
// Finalize the return check by taking the LUB of the return types
// we saw and assigning it to the expected return type. This isn't
// really expected to fail, since the coercions would have failed
// earlier when trying to find a LUB.
let coercion = fcx.ret_coercion.take().unwrap().into_inner();
let mut actual_return_ty = coercion.complete(&fcx);
debug!("actual_return_ty = {:?}", actual_return_ty);
if let ty::Dynamic(..) = declared_ret_ty.kind() {
// We have special-cased the case where the function is declared
// `-> dyn Foo` and we don't actually relate it to the
// `fcx.ret_coercion`, so just substitute a type variable.
actual_return_ty =
fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span });
debug!("actual_return_ty replaced with {:?}", actual_return_ty);
}
// HACK(oli-obk, compiler-errors): We should be comparing this against
// `declared_ret_ty`, but then anything uninferred would be inferred to
// the opaque type itself. That again would cause writeback to assume
// we have a recursive call site and do the sadly stabilized fallback to `()`.
fcx.demand_suptype(span, ret_ty, actual_return_ty);
// Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
if let Some(panic_impl_did) = tcx.lang_items().panic_impl()
&& panic_impl_did == hir.local_def_id(fn_id).to_def_id()
{
check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
}
// Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
if let Some(alloc_error_handler_did) = tcx.lang_items().oom()
&& alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id()
{
check_alloc_error_fn(tcx, alloc_error_handler_did.expect_local(), fn_sig, decl, declared_ret_ty);
}
(fcx, gen_ty)
}
fn check_panic_info_fn(
tcx: TyCtxt<'_>,
fn_id: LocalDefId,
fn_sig: ty::FnSig<'_>,
decl: &hir::FnDecl<'_>,
declared_ret_ty: Ty<'_>,
) {
let Some(panic_info_did) = tcx.lang_items().panic_info() else {
tcx.sess.err("language item required, but not found: `panic_info`");
return;
};
if *declared_ret_ty.kind() != ty::Never {
tcx.sess.span_err(decl.output.span(), "return type should be `!`");
}
let inputs = fn_sig.inputs();
if inputs.len() != 1 {
tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
return;
}
let arg_is_panic_info = match *inputs[0].kind() {
ty::Ref(region, ty, mutbl) => match *ty.kind() {
ty::Adt(ref adt, _) => {
adt.did() == panic_info_did && mutbl == hir::Mutability::Not && !region.is_static()
}
_ => false,
},
_ => false,
};
if !arg_is_panic_info {
tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
}
let DefKind::Fn = tcx.def_kind(fn_id) else {
let span = tcx.def_span(fn_id);
tcx.sess.span_err(span, "should be a function");
return;
};
let generic_counts = tcx.generics_of(fn_id).own_counts();
if generic_counts.types != 0 {
let span = tcx.def_span(fn_id);
tcx.sess.span_err(span, "should have no type parameters");
}
if generic_counts.consts != 0 {
let span = tcx.def_span(fn_id);
tcx.sess.span_err(span, "should have no const parameters");
}
}
fn check_alloc_error_fn(
tcx: TyCtxt<'_>,
fn_id: LocalDefId,
fn_sig: ty::FnSig<'_>,
decl: &hir::FnDecl<'_>,
declared_ret_ty: Ty<'_>,
) {
let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() else {
tcx.sess.err("language item required, but not found: `alloc_layout`");
return;
};
if *declared_ret_ty.kind() != ty::Never {
tcx.sess.span_err(decl.output.span(), "return type should be `!`");
}
let inputs = fn_sig.inputs();
if inputs.len() != 1 {
tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
return;
}
let arg_is_alloc_layout = match inputs[0].kind() {
ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
_ => false,
};
if !arg_is_alloc_layout {
tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
}
let DefKind::Fn = tcx.def_kind(fn_id) else {
let span = tcx.def_span(fn_id);
tcx.sess.span_err(span, "`#[alloc_error_handler]` should be a function");
return;
};
let generic_counts = tcx.generics_of(fn_id).own_counts();
if generic_counts.types != 0 {
let span = tcx.def_span(fn_id);
tcx.sess.span_err(span, "`#[alloc_error_handler]` function should have no type parameters");
}
if generic_counts.consts != 0 {
let span = tcx.def_span(fn_id);
tcx.sess
.span_err(span, "`#[alloc_error_handler]` function should have no const parameters");
}
}
fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let def = tcx.adt_def(def_id);
let span = tcx.def_span(def_id);

View file

@ -1,117 +1,11 @@
use hir::HirId;
use rustc_ast::InlineAsmTemplatePiece;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_index::vec::Idx;
use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitable, UintTy};
use rustc_session::lint;
use rustc_span::{Symbol, DUMMY_SP};
use rustc_target::abi::{Pointer, VariantIdx};
use rustc_target::asm::{InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType};
use super::FnCtxt;
/// If the type is `Option<T>`, it will return `T`, otherwise
/// the type itself. Works on most `Option`-like types.
fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
let ty::Adt(def, substs) = *ty.kind() else { return ty };
if def.variants().len() == 2 && !def.repr().c() && def.repr().int.is_none() {
let data_idx;
let one = VariantIdx::new(1);
let zero = VariantIdx::new(0);
if def.variant(zero).fields.is_empty() {
data_idx = one;
} else if def.variant(one).fields.is_empty() {
data_idx = zero;
} else {
return ty;
}
if def.variant(data_idx).fields.len() == 1 {
return def.variant(data_idx).fields[0].ty(tcx, substs);
}
}
ty
}
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) {
let tcx = self.tcx;
let span = tcx.hir().span(hir_id);
let normalize = |ty| {
let ty = self.resolve_vars_if_possible(ty);
self.tcx.normalize_erasing_regions(self.param_env, ty)
};
let from = normalize(from);
let to = normalize(to);
trace!(?from, ?to);
// Transmutes that are only changing lifetimes are always ok.
if from == to {
return;
}
let skel = |ty| SizeSkeleton::compute(ty, tcx, self.param_env);
let sk_from = skel(from);
let sk_to = skel(to);
trace!(?sk_from, ?sk_to);
// Check for same size using the skeletons.
if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) {
if sk_from.same_size(sk_to) {
return;
}
// Special-case transmuting from `typeof(function)` and
// `Option<typeof(function)>` to present a clearer error.
let from = unpack_option_like(tcx, from);
if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer.size(&tcx) {
struct_span_err!(tcx.sess, span, E0591, "can't transmute zero-sized type")
.note(&format!("source type: {from}"))
.note(&format!("target type: {to}"))
.help("cast with `as` to a pointer instead")
.emit();
return;
}
}
// Try to display a sensible error with as much information as possible.
let skeleton_string = |ty: Ty<'tcx>, sk| match sk {
Ok(SizeSkeleton::Known(size)) => format!("{} bits", size.bits()),
Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"),
Err(LayoutError::Unknown(bad)) => {
if bad == ty {
"this type does not have a fixed size".to_owned()
} else {
format!("size can vary because of {bad}")
}
}
Err(err) => err.to_string(),
};
let mut err = struct_span_err!(
tcx.sess,
span,
E0512,
"cannot transmute between types of different sizes, \
or dependently-sized types"
);
if from == to {
err.note(&format!("`{from}` does not have a fixed size"));
} else {
err.note(&format!("source type: `{}` ({})", from, skeleton_string(from, sk_from)))
.note(&format!("target type: `{}` ({})", to, skeleton_string(to, sk_to)));
}
err.emit();
}
}
pub struct InlineAsmCtxt<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,

View file

@ -62,191 +62,45 @@
*/
pub mod _match;
mod autoderef;
mod callee;
pub mod cast;
mod check;
mod closure;
pub mod coercion;
mod compare_method;
pub mod demand;
mod diverges;
pub mod dropck;
mod expectation;
mod expr;
mod fallback;
mod fn_ctxt;
mod gather_locals;
mod generator_interior;
mod inherited;
pub mod intrinsic;
mod intrinsicck;
pub mod method;
mod op;
mod pat;
mod place_op;
pub mod intrinsicck;
mod region;
pub mod rvalue_scopes;
mod upvar;
pub mod wfcheck;
pub mod writeback;
use check::{check_abi, check_fn, check_mod_item_types};
pub use diverges::Diverges;
pub use expectation::Expectation;
pub use fn_ctxt::*;
pub use inherited::{Inherited, InheritedBuilder};
pub use check::check_abi;
use crate::astconv::AstConv;
use crate::check::gather_locals::GatherLocalsVisitor;
use check::check_mod_item_types;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan,
};
use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
use rustc_hir::{HirIdMap, ImplicitSelfKind, Node};
use rustc_index::bit_set::BitSet;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, Ty, TyCtxt, UserType};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{InternalSubsts, SubstsRef};
use rustc_session::config;
use rustc_session::parse::feature_err;
use rustc_session::Session;
use rustc_span::source_map::DUMMY_SP;
use rustc_span::symbol::{kw, Ident};
use rustc_span::{self, BytePos, Span, Symbol};
use rustc_target::abi::VariantIdx;
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
use std::cell::RefCell;
use std::num::NonZeroU32;
use crate::require_c_abi_if_c_variadic;
use crate::util::common::indenter;
use self::coercion::DynamicCoerceMany;
use self::compare_method::collect_trait_impl_trait_tys;
use self::region::region_scope_tree;
pub use self::Expectation::*;
#[macro_export]
macro_rules! type_error_struct {
($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({
let mut err = rustc_errors::struct_span_err!($session, $span, $code, $($message)*);
if $typ.references_error() {
err.downgrade_to_delayed_bug();
}
err
})
}
/// The type of a local binding, including the revealed type for anon types.
#[derive(Copy, Clone, Debug)]
pub struct LocalTy<'tcx> {
decl_ty: Ty<'tcx>,
revealed_ty: Ty<'tcx>,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Needs {
MutPlace,
None,
}
impl Needs {
fn maybe_mut_place(m: hir::Mutability) -> Self {
match m {
hir::Mutability::Mut => Needs::MutPlace,
hir::Mutability::Not => Needs::None,
}
}
}
#[derive(Copy, Clone)]
pub struct UnsafetyState {
pub def: hir::HirId,
pub unsafety: hir::Unsafety,
from_fn: bool,
}
impl UnsafetyState {
pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState {
UnsafetyState { def, unsafety, from_fn: true }
}
pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState {
use hir::BlockCheckMode;
match self.unsafety {
// If this unsafe, then if the outer function was already marked as
// unsafe we shouldn't attribute the unsafe'ness to the block. This
// way the block can be warned about instead of ignoring this
// extraneous block (functions are never warned about).
hir::Unsafety::Unsafe if self.from_fn => self,
unsafety => {
let (unsafety, def) = match blk.rules {
BlockCheckMode::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.hir_id),
BlockCheckMode::DefaultBlock => (unsafety, self.def),
};
UnsafetyState { def, unsafety, from_fn: false }
}
}
}
}
#[derive(Debug, Copy, Clone)]
pub enum PlaceOp {
Deref,
Index,
}
pub struct BreakableCtxt<'tcx> {
may_break: bool,
// this is `null` for loops where break with a value is illegal,
// such as `while`, `for`, and `while let`
coerce: Option<DynamicCoerceMany<'tcx>>,
}
pub struct EnclosingBreakables<'tcx> {
stack: Vec<BreakableCtxt<'tcx>>,
by_id: HirIdMap<usize>,
}
impl<'tcx> EnclosingBreakables<'tcx> {
fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> {
self.opt_find_breakable(target_id).unwrap_or_else(|| {
bug!("could not find enclosing breakable with id {}", target_id);
})
}
fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> {
match self.by_id.get(&target_id) {
Some(ix) => Some(&mut self.stack[*ix]),
None => None,
}
}
}
pub fn provide(providers: &mut Providers) {
method::provide(providers);
wfcheck::provide(providers);
*providers = Providers {
typeck_item_bodies,
typeck_const_arg,
typeck,
diagnostic_only_typeck,
has_typeck_results,
adt_destructor,
used_trait_imports,
check_mod_item_types,
region_scope_tree,
collect_trait_impl_trait_tys,
@ -259,259 +113,6 @@ fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> {
tcx.calculate_dtor(def_id, dropck::check_drop_impl)
}
/// If this `DefId` is a "primary tables entry", returns
/// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
///
/// If this function returns `Some`, then `typeck_results(def_id)` will
/// succeed; if it returns `None`, then `typeck_results(def_id)` may or
/// may not succeed. In some cases where this function returns `None`
/// (notably closures), `typeck_results(def_id)` would wind up
/// redirecting to the owning function.
fn primary_body_of(
tcx: TyCtxt<'_>,
id: hir::HirId,
) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
match tcx.hir().get(id) {
Node::Item(item) => match item.kind {
hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => {
Some((body, Some(ty), None))
}
hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))),
_ => None,
},
Node::TraitItem(item) => match item.kind {
hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)),
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
Some((body, None, Some(sig)))
}
_ => None,
},
Node::ImplItem(item) => match item.kind {
hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)),
hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))),
_ => None,
},
Node::AnonConst(constant) => Some((constant.body, None, None)),
_ => None,
}
}
fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
// Closures' typeck results come from their outermost function,
// as they are part of the same "inference environment".
let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
if typeck_root_def_id != def_id {
return tcx.has_typeck_results(typeck_root_def_id);
}
if let Some(def_id) = def_id.as_local() {
let id = tcx.hir().local_def_id_to_hir_id(def_id);
primary_body_of(tcx, id).is_some()
} else {
false
}
}
fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDefId> {
&*tcx.typeck(def_id).used_trait_imports
}
fn typeck_const_arg<'tcx>(
tcx: TyCtxt<'tcx>,
(did, param_did): (LocalDefId, DefId),
) -> &ty::TypeckResults<'tcx> {
let fallback = move || tcx.type_of(param_did);
typeck_with_fallback(tcx, did, fallback)
}
fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
if let Some(param_did) = tcx.opt_const_param_of(def_id) {
tcx.typeck_const_arg((def_id, param_did))
} else {
let fallback = move || tcx.type_of(def_id.to_def_id());
typeck_with_fallback(tcx, def_id, fallback)
}
}
/// Used only to get `TypeckResults` for type inference during error recovery.
/// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors.
fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
let fallback = move || {
let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id));
tcx.ty_error_with_message(span, "diagnostic only typeck table used")
};
typeck_with_fallback(tcx, def_id, fallback)
}
fn typeck_with_fallback<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
fallback: impl Fn() -> Ty<'tcx> + 'tcx,
) -> &'tcx ty::TypeckResults<'tcx> {
// Closures' typeck results come from their outermost function,
// as they are part of the same "inference environment".
let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
if typeck_root_def_id != def_id {
return tcx.typeck(typeck_root_def_id);
}
let id = tcx.hir().local_def_id_to_hir_id(def_id);
let span = tcx.hir().span(id);
// Figure out what primary body this item has.
let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| {
span_bug!(span, "can't type-check body of {:?}", def_id);
});
let body = tcx.hir().body(body_id);
let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
let param_env = tcx.param_env(def_id);
let mut fcx = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
<dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
} else {
tcx.fn_sig(def_id)
};
check_abi(tcx, id, span, fn_sig.abi());
// Compute the function signature from point of view of inside the fn.
let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
let fn_sig = inh.normalize_associated_types_in(
body.value.span,
body_id.hir_id,
param_env,
fn_sig,
);
check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0
} else {
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
let expected_type = body_ty
.and_then(|ty| match ty.kind {
hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)),
_ => None,
})
.unwrap_or_else(|| match tcx.hir().get(id) {
Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) {
Node::Expr(&hir::Expr {
kind: hir::ExprKind::ConstBlock(ref anon_const),
..
}) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeInference,
span,
}),
Node::Ty(&hir::Ty {
kind: hir::TyKind::Typeof(ref anon_const), ..
}) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeInference,
span,
}),
Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
| Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
let operand_ty = asm
.operands
.iter()
.filter_map(|(op, _op_sp)| match op {
hir::InlineAsmOperand::Const { anon_const }
if anon_const.hir_id == id =>
{
// Inline assembly constants must be integers.
Some(fcx.next_int_var())
}
hir::InlineAsmOperand::SymFn { anon_const }
if anon_const.hir_id == id =>
{
Some(fcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::MiscVariable,
span,
}))
}
_ => None,
})
.next();
operand_ty.unwrap_or_else(fallback)
}
_ => fallback(),
},
_ => fallback(),
});
let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type);
fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
// Gather locals in statics (because of block expressions).
GatherLocalsVisitor::new(&fcx).visit_body(body);
fcx.check_expr_coercable_to_type(&body.value, expected_type, None);
fcx.write_ty(id, expected_type);
fcx
};
let fallback_has_occurred = fcx.type_inference_fallback();
// Even though coercion casts provide type hints, we check casts after fallback for
// backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
fcx.check_casts();
fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
// Closure and generator analysis may run after fallback
// because they don't constrain other type variables.
// Closure analysis only runs on closures. Therefore they only need to fulfill non-const predicates (as of now)
let prev_constness = fcx.param_env.constness();
fcx.param_env = fcx.param_env.without_const();
fcx.closure_analyze(body);
fcx.param_env = fcx.param_env.with_constness(prev_constness);
assert!(fcx.deferred_call_resolutions.borrow().is_empty());
// Before the generator analysis, temporary scopes shall be marked to provide more
// precise information on types to be captured.
fcx.resolve_rvalue_scopes(def_id.to_def_id());
fcx.resolve_generator_interiors(def_id.to_def_id());
for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
let ty = fcx.normalize_ty(span, ty);
fcx.require_type_is_sized(ty, span, code);
}
fcx.select_all_obligations_or_error();
if !fcx.infcx.is_tainted_by_errors() {
fcx.check_transmutes();
}
fcx.check_asms();
fcx.infcx.skip_region_resolution();
fcx.resolve_type_vars_in_body(body)
});
// Consistency check our TypeckResults instance can hold all ItemLocalIds
// it will need to hold.
assert_eq!(typeck_results.hir_owner, id.owner);
typeck_results
}
/// When `check_fn` is invoked on a generator (i.e., a body that
/// includes yield), it returns back some information about the yield
/// points.
struct GeneratorTypes<'tcx> {
/// Type of generator argument / values returned by `yield`.
resume_ty: Ty<'tcx>,
/// Type of value that is yielded.
yield_ty: Ty<'tcx>,
/// Types that are captured (see `GeneratorInterior` for more).
interior: Ty<'tcx>,
/// Indicates if the generator is movable or static (immovable).
movability: hir::Movability,
}
/// Given a `DefId` for an opaque type in return position, find its parent item's return
/// expressions.
fn get_owner_return_paths<'tcx>(
@ -528,9 +129,10 @@ fn get_owner_return_paths<'tcx>(
})
}
// Forbid defining intrinsics in Rust code,
// as they must always be defined by the compiler.
fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
/// Forbid defining intrinsics in Rust code,
/// as they must always be defined by the compiler.
// FIXME: Move this to a more appropriate place.
pub fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block");
}
@ -824,6 +426,17 @@ fn fn_sig_suggestion<'tcx>(
format!("{unsafety}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}")
}
pub fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> {
Some(match ty.kind() {
ty::Bool => "true",
ty::Char => "'a'",
ty::Int(_) | ty::Uint(_) => "42",
ty::Float(_) => "3.14159",
ty::Error(_) | ty::Never => return None,
_ => "value",
})
}
/// Return placeholder code for the given associated item.
/// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
/// structured suggestion.
@ -845,7 +458,7 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
ty::AssocKind::Type => format!("type {} = Type;", assoc.name),
ty::AssocKind::Const => {
let ty = tcx.type_of(assoc.def_id);
let val = expr::ty_kind_suggestion(ty).unwrap_or("value");
let val = ty_kind_suggestion(ty).unwrap_or("value");
format!("const {}: {} = {};", assoc.name, ty, val)
}
}
@ -896,76 +509,7 @@ fn bad_non_zero_sized_fields<'tcx>(
err.emit();
}
fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'_>, span: Span) {
struct_span_err!(
tcx.sess,
span,
E0533,
"expected unit struct, unit variant or constant, found {} `{}`",
res.descr(),
rustc_hir_pretty::qpath_to_string(qpath),
)
.emit();
}
/// Controls whether the arguments are tupled. This is used for the call
/// operator.
///
/// Tupling means that all call-side arguments are packed into a tuple and
/// passed as a single parameter. For example, if tupling is enabled, this
/// function:
/// ```
/// fn f(x: (isize, isize)) {}
/// ```
/// Can be called as:
/// ```ignore UNSOLVED (can this be done in user code?)
/// # fn f(x: (isize, isize)) {}
/// f(1, 2);
/// ```
/// Instead of:
/// ```
/// # fn f(x: (isize, isize)) {}
/// f((1, 2));
/// ```
#[derive(Clone, Eq, PartialEq)]
enum TupleArgumentsFlag {
DontTupleArguments,
TupleArguments,
}
fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
}
fn fatally_break_rust(sess: &Session) {
let handler = sess.diagnostic();
handler.span_bug_no_panic(
MultiSpan::new(),
"It looks like you're trying to break rust; would you like some ICE?",
);
handler.note_without_error("the compiler expectedly panicked. this is a feature.");
handler.note_without_error(
"we would appreciate a joke overview: \
https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
);
handler.note_without_error(&format!(
"rustc {} running on {}",
option_env!("CFG_VERSION").unwrap_or("unknown_version"),
config::host_triple(),
));
}
fn potentially_plural_count(count: usize, word: &str) -> String {
// FIXME: Consider moving this method to a more fitting place.
pub fn potentially_plural_count(count: usize, word: &str) -> String {
format!("{} {}{}", count, word, pluralize!(count))
}
fn has_expected_num_generic_args<'tcx>(
tcx: TyCtxt<'tcx>,
trait_did: Option<DefId>,
expected: usize,
) -> bool {
trait_did.map_or(true, |trait_did| {
let generics = tcx.generics_of(trait_did);
generics.count() == expected + if generics.has_self { 1 } else { 0 }
})
}

View file

@ -1,22 +1,11 @@
//! Errors emitted by `hir_analysis`.
//! Errors emitted by `rustc_hir_analysis`.
use rustc_errors::IntoDiagnostic;
use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_macros::{Diagnostic, LintDiagnostic};
use rustc_middle::ty::Ty;
use rustc_span::{symbol::Ident, Span, Symbol};
#[derive(Diagnostic)]
#[diag(hir_analysis::field_multiply_specified_in_initializer, code = "E0062")]
pub struct FieldMultiplySpecifiedInInitializer {
#[primary_span]
#[label]
pub span: Span,
#[label(hir_analysis::previous_use_label)]
pub prev_span: Span,
pub ident: Ident,
}
#[derive(Diagnostic)]
#[diag(hir_analysis::unrecognized_atomic_operation, code = "E0092")]
pub struct UnrecognizedAtomicOperation<'a> {
@ -124,13 +113,6 @@ pub struct AssocTypeBindingNotAllowed {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis::functional_record_update_on_non_struct, code = "E0436")]
pub struct FunctionalRecordUpdateOnNonStruct {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis::typeof_reserved_keyword_used, code = "E0516")]
pub struct TypeofReservedKeywordUsed<'tcx> {
@ -142,39 +124,6 @@ pub struct TypeofReservedKeywordUsed<'tcx> {
pub opt_sugg: Option<(Span, Applicability)>,
}
#[derive(Diagnostic)]
#[diag(hir_analysis::return_stmt_outside_of_fn_body, code = "E0572")]
pub struct ReturnStmtOutsideOfFnBody {
#[primary_span]
pub span: Span,
#[label(hir_analysis::encl_body_label)]
pub encl_body_span: Option<Span>,
#[label(hir_analysis::encl_fn_label)]
pub encl_fn_span: Option<Span>,
}
#[derive(Diagnostic)]
#[diag(hir_analysis::yield_expr_outside_of_generator, code = "E0627")]
pub struct YieldExprOutsideOfGenerator {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis::struct_expr_non_exhaustive, code = "E0639")]
pub struct StructExprNonExhaustive {
#[primary_span]
pub span: Span,
pub what: &'static str,
}
#[derive(Diagnostic)]
#[diag(hir_analysis::method_call_on_unknown_type, code = "E0699")]
pub struct MethodCallOnUnknownType {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis::value_of_associated_struct_already_specified, code = "E0719")]
pub struct ValueOfAssociatedStructAlreadySpecified {
@ -187,52 +136,6 @@ pub struct ValueOfAssociatedStructAlreadySpecified {
pub def_path: String,
}
#[derive(Diagnostic)]
#[diag(hir_analysis::address_of_temporary_taken, code = "E0745")]
pub struct AddressOfTemporaryTaken {
#[primary_span]
#[label]
pub span: Span,
}
#[derive(Subdiagnostic)]
pub enum AddReturnTypeSuggestion {
#[suggestion(
hir_analysis::add_return_type_add,
code = "-> {found} ",
applicability = "machine-applicable"
)]
Add {
#[primary_span]
span: Span,
found: String,
},
#[suggestion(
hir_analysis::add_return_type_missing_here,
code = "-> _ ",
applicability = "has-placeholders"
)]
MissingHere {
#[primary_span]
span: Span,
},
}
#[derive(Subdiagnostic)]
pub enum ExpectedReturnTypeLabel<'tcx> {
#[label(hir_analysis::expected_default_return_type)]
Unit {
#[primary_span]
span: Span,
},
#[label(hir_analysis::expected_return_type)]
Other {
#[primary_span]
span: Span,
expected: Ty<'tcx>,
},
}
#[derive(Diagnostic)]
#[diag(hir_analysis::unconstrained_opaque_type)]
#[note]
@ -346,29 +249,3 @@ pub struct ExpectedUsedSymbol {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis::missing_parentheses_in_range, code = "E0689")]
pub struct MissingParentheseInRange {
#[primary_span]
#[label(hir_analysis::missing_parentheses_in_range)]
pub span: Span,
pub ty_str: String,
pub method_name: String,
#[subdiagnostic]
pub add_missing_parentheses: Option<AddMissingParenthesesInRange>,
}
#[derive(Subdiagnostic)]
#[multipart_suggestion_verbose(
hir_analysis::add_missing_parentheses_in_range,
applicability = "maybe-incorrect"
)]
pub struct AddMissingParenthesesInRange {
pub func_name: String,
#[suggestion_part(code = "(")]
pub left: Span,
#[suggestion_part(code = ")")]
pub right: Span,
}

View file

@ -82,20 +82,19 @@
// These are used by Clippy.
pub mod check;
pub mod expr_use_visitor;
mod astconv;
pub mod astconv;
mod bounds;
mod check_unused;
mod coherence;
mod collect;
// FIXME: This module shouldn't be public.
pub mod collect;
mod constrained_generic_params;
mod errors;
pub mod hir_wf_check;
mod impl_wf_check;
mod mem_categorization;
mod outlives;
mod structured_errors;
pub mod structured_errors;
mod variance;
use rustc_errors::{struct_span_err, ErrorGuaranteed};

View file

@ -0,0 +1,28 @@
[package]
name = "rustc_hir_typeck"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
tracing = "0.1"
rustc_ast = { path = "../rustc_ast" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_graphviz = { path = "../rustc_graphviz" }
rustc_index = { path = "../rustc_index" }
rustc_infer = { path = "../rustc_infer" }
rustc_hir = { path = "../rustc_hir" }
rustc_hir_analysis = { path = "../rustc_hir_analysis" }
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
rustc_lint = { path = "../rustc_lint" }
rustc_middle = { path = "../rustc_middle" }
rustc_macros = { path = "../rustc_macros" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
rustc_type_ir = { path = "../rustc_type_ir" }

View file

@ -1,5 +1,5 @@
use crate::check::coercion::{AsCoercionSite, CoerceMany};
use crate::check::{Diverges, Expectation, FnCtxt, Needs};
use crate::coercion::{AsCoercionSite, CoerceMany};
use crate::{Diverges, Expectation, FnCtxt, Needs};
use rustc_errors::{Applicability, MultiSpan};
use rustc_hir::{self as hir, ExprKind};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};

View file

@ -1,8 +1,8 @@
use super::method::probe::{IsSuggestion, Mode, ProbeScope};
use super::method::MethodCallee;
use super::{Expectation, FnCtxt, TupleArgumentsFlag};
use crate::type_error_struct;
use crate::type_error_struct;
use rustc_ast::util::parser::PREC_POSTFIX;
use rustc_errors::{struct_span_err, Applicability, Diagnostic, StashKey};
use rustc_hir as hir;

View file

@ -30,9 +30,7 @@
use super::FnCtxt;
use crate::hir::def_id::DefId;
use crate::type_error_struct;
use hir::def_id::LOCAL_CRATE;
use rustc_errors::{struct_span_err, Applicability, DelayDm, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_middle::mir::Mutability;
@ -43,6 +41,7 @@
use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable, VariantDef};
use rustc_session::lint;
use rustc_session::Session;
use rustc_span::def_id::{DefId, LOCAL_CRATE};
use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
@ -527,7 +526,9 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
err.emit();
}
CastError::SizedUnsizedCast => {
use crate::structured_errors::{SizedUnsizedCast, StructuredDiagnostic};
use rustc_hir_analysis::structured_errors::{
SizedUnsizedCast, StructuredDiagnostic,
};
SizedUnsizedCast {
sess: &fcx.tcx.sess,

View file

@ -0,0 +1,324 @@
use crate::coercion::CoerceMany;
use crate::gather_locals::GatherLocalsVisitor;
use crate::{FnCtxt, Inherited};
use crate::{GeneratorTypes, UnsafetyState};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{ImplicitSelfKind, ItemKind, Node};
use rustc_hir_analysis::check::fn_maybe_err;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::RegionVariableOrigin;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::def_id::LocalDefId;
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits;
use std::cell::RefCell;
/// Helper used for fns and closures. Does the grungy work of checking a function
/// body and returns the function context used for that purpose, since in the case of a fn item
/// there is still a bit more to do.
///
/// * ...
/// * inherited: other fields inherited from the enclosing fn (if any)
#[instrument(skip(inherited, body), level = "debug")]
pub(super) fn check_fn<'a, 'tcx>(
inherited: &'a Inherited<'tcx>,
param_env: ty::ParamEnv<'tcx>,
fn_sig: ty::FnSig<'tcx>,
decl: &'tcx hir::FnDecl<'tcx>,
fn_id: hir::HirId,
body: &'tcx hir::Body<'tcx>,
can_be_generator: Option<hir::Movability>,
return_type_pre_known: bool,
) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
// Create the function context. This is either derived from scratch or,
// in the case of closures, based on the outer context.
let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
fcx.ps.set(UnsafetyState::function(fn_sig.unsafety, fn_id));
fcx.return_type_pre_known = return_type_pre_known;
let tcx = fcx.tcx;
let hir = tcx.hir();
let declared_ret_ty = fn_sig.output();
let ret_ty =
fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars(
declared_ret_ty,
body.value.hir_id,
decl.output.span(),
param_env,
));
// If we replaced declared_ret_ty with infer vars, then we must be inferring
// an opaque type, so set a flag so we can improve diagnostics.
fcx.return_type_has_opaque = ret_ty != declared_ret_ty;
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
let span = body.value.span;
fn_maybe_err(tcx, span, fn_sig.abi);
if fn_sig.abi == Abi::RustCall {
let expected_args = if let ImplicitSelfKind::None = decl.implicit_self { 1 } else { 2 };
let err = || {
let item = match tcx.hir().get(fn_id) {
Node::Item(hir::Item { kind: ItemKind::Fn(header, ..), .. }) => Some(header),
Node::ImplItem(hir::ImplItem {
kind: hir::ImplItemKind::Fn(header, ..), ..
}) => Some(header),
Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Fn(header, ..),
..
}) => Some(header),
// Closures are RustCall, but they tuple their arguments, so shouldn't be checked
Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => None,
node => bug!("Item being checked wasn't a function/closure: {:?}", node),
};
if let Some(header) = item {
tcx.sess.span_err(header.span, "functions with the \"rust-call\" ABI must take a single non-self argument that is a tuple");
}
};
if fn_sig.inputs().len() != expected_args {
err()
} else {
// FIXME(CraftSpider) Add a check on parameter expansion, so we don't just make the ICE happen later on
// This will probably require wide-scale changes to support a TupleKind obligation
// We can't resolve this without knowing the type of the param
if !matches!(fn_sig.inputs()[expected_args - 1].kind(), ty::Tuple(_) | ty::Param(_)) {
err()
}
}
}
if body.generator_kind.is_some() && can_be_generator.is_some() {
let yield_ty = fcx
.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
// Resume type defaults to `()` if the generator has no argument.
let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit());
fcx.resume_yield_tys = Some((resume_ty, yield_ty));
}
GatherLocalsVisitor::new(&fcx).visit_body(body);
// C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
// (as it's created inside the body itself, not passed in from outside).
let maybe_va_list = if fn_sig.c_variadic {
let span = body.params.last().unwrap().span;
let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span));
let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span));
Some(tcx.bound_type_of(va_list_did).subst(tcx, &[region.into()]))
} else {
None
};
// Add formal parameters.
let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs);
let inputs_fn = fn_sig.inputs().iter().copied();
for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
// Check the pattern.
let ty_span = try { inputs_hir?.get(idx)?.span };
fcx.check_pat_top(&param.pat, param_ty, ty_span, false);
// Check that argument is Sized.
// The check for a non-trivial pattern is a hack to avoid duplicate warnings
// for simple cases like `fn foo(x: Trait)`,
// where we would error once on the parameter as a whole, and once on the binding `x`.
if param.pat.simple_ident().is_none() && !tcx.features().unsized_fn_params {
fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
}
fcx.write_ty(param.hir_id, param_ty);
}
inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
fcx.in_tail_expr = true;
if let ty::Dynamic(..) = declared_ret_ty.kind() {
// FIXME: We need to verify that the return type is `Sized` after the return expression has
// been evaluated so that we have types available for all the nodes being returned, but that
// requires the coerced evaluated type to be stored. Moving `check_return_expr` before this
// causes unsized errors caused by the `declared_ret_ty` to point at the return expression,
// while keeping the current ordering we will ignore the tail expression's type because we
// don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr`
// because we will trigger "unreachable expression" lints unconditionally.
// Because of all of this, we perform a crude check to know whether the simplest `!Sized`
// case that a newcomer might make, returning a bare trait, and in that case we populate
// the tail expression's type so that the suggestion will be correct, but ignore all other
// possible cases.
fcx.check_expr(&body.value);
fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
} else {
fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
fcx.check_return_expr(&body.value, false);
}
fcx.in_tail_expr = false;
// We insert the deferred_generator_interiors entry after visiting the body.
// This ensures that all nested generators appear before the entry of this generator.
// resolve_generator_interiors relies on this property.
let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) {
let interior = fcx
.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span });
fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind));
let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap();
Some(GeneratorTypes {
resume_ty,
yield_ty,
interior,
movability: can_be_generator.unwrap(),
})
} else {
None
};
// Finalize the return check by taking the LUB of the return types
// we saw and assigning it to the expected return type. This isn't
// really expected to fail, since the coercions would have failed
// earlier when trying to find a LUB.
let coercion = fcx.ret_coercion.take().unwrap().into_inner();
let mut actual_return_ty = coercion.complete(&fcx);
debug!("actual_return_ty = {:?}", actual_return_ty);
if let ty::Dynamic(..) = declared_ret_ty.kind() {
// We have special-cased the case where the function is declared
// `-> dyn Foo` and we don't actually relate it to the
// `fcx.ret_coercion`, so just substitute a type variable.
actual_return_ty =
fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span });
debug!("actual_return_ty replaced with {:?}", actual_return_ty);
}
// HACK(oli-obk, compiler-errors): We should be comparing this against
// `declared_ret_ty`, but then anything uninferred would be inferred to
// the opaque type itself. That again would cause writeback to assume
// we have a recursive call site and do the sadly stabilized fallback to `()`.
fcx.demand_suptype(span, ret_ty, actual_return_ty);
// Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
if let Some(panic_impl_did) = tcx.lang_items().panic_impl()
&& panic_impl_did == hir.local_def_id(fn_id).to_def_id()
{
check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
}
// Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
if let Some(alloc_error_handler_did) = tcx.lang_items().oom()
&& alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id()
{
check_alloc_error_fn(tcx, alloc_error_handler_did.expect_local(), fn_sig, decl, declared_ret_ty);
}
(fcx, gen_ty)
}
fn check_panic_info_fn(
tcx: TyCtxt<'_>,
fn_id: LocalDefId,
fn_sig: ty::FnSig<'_>,
decl: &hir::FnDecl<'_>,
declared_ret_ty: Ty<'_>,
) {
let Some(panic_info_did) = tcx.lang_items().panic_info() else {
tcx.sess.err("language item required, but not found: `panic_info`");
return;
};
if *declared_ret_ty.kind() != ty::Never {
tcx.sess.span_err(decl.output.span(), "return type should be `!`");
}
let inputs = fn_sig.inputs();
if inputs.len() != 1 {
tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
return;
}
let arg_is_panic_info = match *inputs[0].kind() {
ty::Ref(region, ty, mutbl) => match *ty.kind() {
ty::Adt(ref adt, _) => {
adt.did() == panic_info_did && mutbl == hir::Mutability::Not && !region.is_static()
}
_ => false,
},
_ => false,
};
if !arg_is_panic_info {
tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
}
let DefKind::Fn = tcx.def_kind(fn_id) else {
let span = tcx.def_span(fn_id);
tcx.sess.span_err(span, "should be a function");
return;
};
let generic_counts = tcx.generics_of(fn_id).own_counts();
if generic_counts.types != 0 {
let span = tcx.def_span(fn_id);
tcx.sess.span_err(span, "should have no type parameters");
}
if generic_counts.consts != 0 {
let span = tcx.def_span(fn_id);
tcx.sess.span_err(span, "should have no const parameters");
}
}
fn check_alloc_error_fn(
tcx: TyCtxt<'_>,
fn_id: LocalDefId,
fn_sig: ty::FnSig<'_>,
decl: &hir::FnDecl<'_>,
declared_ret_ty: Ty<'_>,
) {
let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() else {
tcx.sess.err("language item required, but not found: `alloc_layout`");
return;
};
if *declared_ret_ty.kind() != ty::Never {
tcx.sess.span_err(decl.output.span(), "return type should be `!`");
}
let inputs = fn_sig.inputs();
if inputs.len() != 1 {
tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
return;
}
let arg_is_alloc_layout = match inputs[0].kind() {
ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
_ => false,
};
if !arg_is_alloc_layout {
tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
}
let DefKind::Fn = tcx.def_kind(fn_id) else {
let span = tcx.def_span(fn_id);
tcx.sess.span_err(span, "`#[alloc_error_handler]` should be a function");
return;
};
let generic_counts = tcx.generics_of(fn_id).own_counts();
if generic_counts.types != 0 {
let span = tcx.def_span(fn_id);
tcx.sess.span_err(span, "`#[alloc_error_handler]` function should have no type parameters");
}
if generic_counts.consts != 0 {
let span = tcx.def_span(fn_id);
tcx.sess
.span_err(span, "`#[alloc_error_handler]` function should have no const parameters");
}
}

View file

@ -2,11 +2,11 @@
use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
use crate::astconv::AstConv;
use hir::def::DefKind;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_infer::infer::{InferOk, InferResult};

View file

@ -35,8 +35,7 @@
//! // and are then unable to coerce `&7i32` to `&mut i32`.
//! ```
use crate::astconv::AstConv;
use crate::check::FnCtxt;
use crate::FnCtxt;
use rustc_errors::{
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
};
@ -44,6 +43,7 @@
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::Expr;
use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{Coercion, InferOk, InferResult};
use rustc_infer::traits::{Obligation, TraitEngine, TraitEngineExt};

View file

@ -1,21 +1,20 @@
use crate::check::FnCtxt;
use rustc_infer::infer::InferOk;
use rustc_middle::middle::stability::EvalResult;
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::ObligationCause;
use crate::FnCtxt;
use rustc_ast::util::parser::PREC_POSTFIX;
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{is_range_literal, Node};
use rustc_infer::infer::InferOk;
use rustc_middle::lint::in_external_macro;
use rustc_middle::middle::stability::EvalResult;
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::{BytePos, Span};
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::ObligationCause;
use super::method::probe;

View file

@ -0,0 +1,127 @@
//! Errors emitted by `rustc_hir_analysis`.
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_middle::ty::Ty;
use rustc_span::{symbol::Ident, Span};
#[derive(Diagnostic)]
#[diag(hir_analysis::field_multiply_specified_in_initializer, code = "E0062")]
pub struct FieldMultiplySpecifiedInInitializer {
#[primary_span]
#[label]
pub span: Span,
#[label(hir_analysis::previous_use_label)]
pub prev_span: Span,
pub ident: Ident,
}
#[derive(Diagnostic)]
#[diag(hir_analysis::return_stmt_outside_of_fn_body, code = "E0572")]
pub struct ReturnStmtOutsideOfFnBody {
#[primary_span]
pub span: Span,
#[label(hir_analysis::encl_body_label)]
pub encl_body_span: Option<Span>,
#[label(hir_analysis::encl_fn_label)]
pub encl_fn_span: Option<Span>,
}
#[derive(Diagnostic)]
#[diag(hir_analysis::yield_expr_outside_of_generator, code = "E0627")]
pub struct YieldExprOutsideOfGenerator {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis::struct_expr_non_exhaustive, code = "E0639")]
pub struct StructExprNonExhaustive {
#[primary_span]
pub span: Span,
pub what: &'static str,
}
#[derive(Diagnostic)]
#[diag(hir_analysis::method_call_on_unknown_type, code = "E0699")]
pub struct MethodCallOnUnknownType {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis::functional_record_update_on_non_struct, code = "E0436")]
pub struct FunctionalRecordUpdateOnNonStruct {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis::address_of_temporary_taken, code = "E0745")]
pub struct AddressOfTemporaryTaken {
#[primary_span]
#[label]
pub span: Span,
}
#[derive(Subdiagnostic)]
pub enum AddReturnTypeSuggestion {
#[suggestion(
hir_analysis::add_return_type_add,
code = "-> {found} ",
applicability = "machine-applicable"
)]
Add {
#[primary_span]
span: Span,
found: String,
},
#[suggestion(
hir_analysis::add_return_type_missing_here,
code = "-> _ ",
applicability = "has-placeholders"
)]
MissingHere {
#[primary_span]
span: Span,
},
}
#[derive(Subdiagnostic)]
pub enum ExpectedReturnTypeLabel<'tcx> {
#[label(hir_analysis::expected_default_return_type)]
Unit {
#[primary_span]
span: Span,
},
#[label(hir_analysis::expected_return_type)]
Other {
#[primary_span]
span: Span,
expected: Ty<'tcx>,
},
}
#[derive(Diagnostic)]
#[diag(hir_analysis::missing_parentheses_in_range, code = "E0689")]
pub struct MissingParentheseInRange {
#[primary_span]
#[label(hir_analysis::missing_parentheses_in_range)]
pub span: Span,
pub ty_str: String,
pub method_name: String,
#[subdiagnostic]
pub add_missing_parentheses: Option<AddMissingParenthesesInRange>,
}
#[derive(Subdiagnostic)]
#[multipart_suggestion_verbose(
hir_analysis::add_missing_parentheses_in_range,
applicability = "maybe-incorrect"
)]
pub struct AddMissingParenthesesInRange {
pub func_name: String,
#[suggestion_part(code = "(")]
pub left: Span,
#[suggestion_part(code = ")")]
pub right: Span,
}

View file

@ -2,23 +2,22 @@
//!
//! See `mod.rs` for more context on type checking in general.
use crate::astconv::AstConv as _;
use crate::check::cast;
use crate::check::coercion::CoerceMany;
use crate::check::fatally_break_rust;
use crate::check::method::SelfSource;
use crate::check::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
use crate::check::{
report_unexpected_variant_res, BreakableCtxt, Diverges, DynamicCoerceMany, FnCtxt, Needs,
TupleArgumentsFlag::DontTupleArguments,
};
use crate::cast;
use crate::coercion::CoerceMany;
use crate::coercion::DynamicCoerceMany;
use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
use crate::errors::{
FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct,
YieldExprOutsideOfGenerator,
};
use crate::fatally_break_rust;
use crate::method::SelfSource;
use crate::type_error_struct;
use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
use crate::{
report_unexpected_variant_res, BreakableCtxt, Diverges, FnCtxt, Needs,
TupleArgumentsFlag::DontTupleArguments,
};
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stack::ensure_sufficient_stack;
@ -32,6 +31,8 @@
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{Closure, ExprKind, HirId, QPath};
use rustc_hir_analysis::astconv::AstConv as _;
use rustc_hir_analysis::check::ty_kind_suggestion;
use rustc_infer::infer;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::InferOk;
@ -1362,7 +1363,7 @@ fn check_expr_const_block(
// Create a new function context.
let fcx = FnCtxt::new(self, self.param_env.with_const(), body.value.hir_id);
crate::check::GatherLocalsVisitor::new(&fcx).visit_body(body);
crate::GatherLocalsVisitor::new(&fcx).visit_body(body);
let ty = fcx.check_expr_with_expectation(&body.value, expected);
fcx.require_type_is_sized(ty, body.value.span, traits::ConstSized);
@ -2885,14 +2886,3 @@ fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>) -> Ty<'tcx> {
}
}
}
pub(super) fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> {
Some(match ty.kind() {
ty::Bool => "true",
ty::Char => "'a'",
ty::Int(_) | ty::Uint(_) => "42",
ty::Float(_) => "3.14159",
ty::Error(_) | ty::Never => return None,
_ => "value",
})
}

View file

@ -89,15 +89,6 @@ enum ConsumeMode {
Move,
}
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum MutateMode {
Init,
/// Example: `x = y`
JustWrite,
/// Example: `x += y`
WriteAndRead,
}
/// The ExprUseVisitor type
///
/// This is the code that actually walks the tree.

View file

@ -1,4 +1,4 @@
use crate::check::FnCtxt;
use crate::FnCtxt;
use rustc_data_structures::{
fx::{FxHashMap, FxHashSet},
graph::WithSuccessors,

View file

@ -1,12 +1,7 @@
use crate::astconv::{
AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
GenericArgCountResult, IsMethodCall, PathSeg,
};
use crate::check::callee::{self, DeferredCallResolution};
use crate::check::method::{self, MethodCallee, SelfSource};
use crate::check::rvalue_scopes;
use crate::check::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
use crate::callee::{self, DeferredCallResolution};
use crate::method::{self, MethodCallee, SelfSource};
use crate::rvalue_scopes;
use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
@ -15,6 +10,10 @@
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{ExprKind, GenericArg, Node, QPath};
use rustc_hir_analysis::astconv::{
AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
GenericArgCountResult, IsMethodCall, PathSeg,
};
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
use rustc_infer::infer::{InferOk, InferResult};
@ -603,9 +602,7 @@ pub(in super::super) fn resolve_generator_interiors(&self, def_id: DefId) {
let mut generators = self.deferred_generator_interiors.borrow_mut();
for (body_id, interior, kind) in generators.drain(..) {
self.select_obligations_where_possible(false, |_| {});
crate::check::generator_interior::resolve_interior(
self, def_id, body_id, interior, kind,
);
crate::generator_interior::resolve_interior(self, def_id, body_id, interior, kind);
}
}

View file

@ -1,19 +1,13 @@
use crate::astconv::AstConv;
use crate::check::coercion::CoerceMany;
use crate::check::fn_ctxt::arg_matrix::{
ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx,
use crate::coercion::CoerceMany;
use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx};
use crate::gather_locals::Declaration;
use crate::method::MethodCallee;
use crate::Expectation::*;
use crate::TupleArgumentsFlag::*;
use crate::{
struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, Needs,
TupleArgumentsFlag,
};
use crate::check::gather_locals::Declaration;
use crate::check::intrinsicck::InlineAsmCtxt;
use crate::check::method::MethodCallee;
use crate::check::Expectation::*;
use crate::check::TupleArgumentsFlag::*;
use crate::check::{
potentially_plural_count, struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt,
LocalTy, Needs, TupleArgumentsFlag,
};
use crate::structured_errors::StructuredDiagnostic;
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{pluralize, Applicability, Diagnostic, DiagnosticId, MultiSpan};
@ -21,6 +15,10 @@
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::{ExprKind, Node, QPath};
use rustc_hir_analysis::astconv::AstConv;
use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt;
use rustc_hir_analysis::check::potentially_plural_count;
use rustc_hir_analysis::structured_errors::StructuredDiagnostic;
use rustc_index::vec::IndexVec;
use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@ -391,7 +389,7 @@ fn variadic_error<'tcx>(
ty: Ty<'tcx>,
cast_ty: &str,
) {
use crate::structured_errors::MissingCastForVariadicArg;
use rustc_hir_analysis::structured_errors::MissingCastForVariadicArg;
MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit();
}

View file

@ -6,12 +6,11 @@
pub use _impl::*;
pub use suggestions::*;
use crate::astconv::AstConv;
use crate::check::coercion::DynamicCoerceMany;
use crate::check::{Diverges, EnclosingBreakables, Inherited, UnsafetyState};
use crate::coercion::DynamicCoerceMany;
use crate::{Diverges, EnclosingBreakables, Inherited, UnsafetyState};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::infer;
use rustc_infer::infer::error_reporting::TypeErrCtxt;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};

View file

@ -1,7 +1,6 @@
use super::FnCtxt;
use crate::astconv::AstConv;
use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
use rustc_errors::{Applicability, Diagnostic, MultiSpan};
use rustc_hir as hir;
@ -10,6 +9,7 @@
use rustc_hir::{
Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
};
use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::infer::{self, TyCtxtInferExt};
use rustc_infer::traits::{self, StatementAsExpression};
use rustc_middle::lint::in_external_macro;

View file

@ -1,9 +1,10 @@
use crate::check::{FnCtxt, LocalTy, UserType};
use crate::{FnCtxt, LocalTy};
use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::PatKind;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::ty::Ty;
use rustc_middle::ty::UserType;
use rustc_span::Span;
use rustc_trait_selection::traits;

View file

@ -14,7 +14,7 @@
use self::cfg_build::build_control_flow_graph;
use self::record_consumed_borrow::find_consumed_and_borrowed;
use crate::check::FnCtxt;
use crate::FnCtxt;
use hir::def_id::DefId;
use hir::{Body, HirId, HirIdMap, Node};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};

View file

@ -1,7 +1,7 @@
use super::TrackedValue;
use crate::{
check::FnCtxt,
expr_use_visitor::{self, ExprUseVisitor},
FnCtxt,
};
use hir::{def_id::DefId, Body, HirId, HirIdMap};
use rustc_data_structures::fx::FxHashSet;

View file

@ -0,0 +1,108 @@
use hir::HirId;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_index::vec::Idx;
use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_target::abi::{Pointer, VariantIdx};
use super::FnCtxt;
/// If the type is `Option<T>`, it will return `T`, otherwise
/// the type itself. Works on most `Option`-like types.
fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
let ty::Adt(def, substs) = *ty.kind() else { return ty };
if def.variants().len() == 2 && !def.repr().c() && def.repr().int.is_none() {
let data_idx;
let one = VariantIdx::new(1);
let zero = VariantIdx::new(0);
if def.variant(zero).fields.is_empty() {
data_idx = one;
} else if def.variant(one).fields.is_empty() {
data_idx = zero;
} else {
return ty;
}
if def.variant(data_idx).fields.len() == 1 {
return def.variant(data_idx).fields[0].ty(tcx, substs);
}
}
ty
}
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) {
let tcx = self.tcx;
let span = tcx.hir().span(hir_id);
let normalize = |ty| {
let ty = self.resolve_vars_if_possible(ty);
self.tcx.normalize_erasing_regions(self.param_env, ty)
};
let from = normalize(from);
let to = normalize(to);
trace!(?from, ?to);
// Transmutes that are only changing lifetimes are always ok.
if from == to {
return;
}
let skel = |ty| SizeSkeleton::compute(ty, tcx, self.param_env);
let sk_from = skel(from);
let sk_to = skel(to);
trace!(?sk_from, ?sk_to);
// Check for same size using the skeletons.
if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) {
if sk_from.same_size(sk_to) {
return;
}
// Special-case transmuting from `typeof(function)` and
// `Option<typeof(function)>` to present a clearer error.
let from = unpack_option_like(tcx, from);
if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer.size(&tcx) {
struct_span_err!(tcx.sess, span, E0591, "can't transmute zero-sized type")
.note(&format!("source type: {from}"))
.note(&format!("target type: {to}"))
.help("cast with `as` to a pointer instead")
.emit();
return;
}
}
// Try to display a sensible error with as much information as possible.
let skeleton_string = |ty: Ty<'tcx>, sk| match sk {
Ok(SizeSkeleton::Known(size)) => format!("{} bits", size.bits()),
Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"),
Err(LayoutError::Unknown(bad)) => {
if bad == ty {
"this type does not have a fixed size".to_owned()
} else {
format!("size can vary because of {bad}")
}
}
Err(err) => err.to_string(),
};
let mut err = struct_span_err!(
tcx.sess,
span,
E0512,
"cannot transmute between types of different sizes, \
or dependently-sized types"
);
if from == to {
err.note(&format!("`{from}` does not have a fixed size"));
} else {
err.note(&format!("source type: `{}` ({})", from, skeleton_string(from, sk_from)))
.note(&format!("target type: `{}` ({})", to, skeleton_string(to, sk_to)));
}
err.emit();
}
}

View file

@ -0,0 +1,506 @@
#![feature(if_let_guard)]
#![feature(let_chains)]
#![feature(try_blocks)]
#![feature(never_type)]
#![feature(min_specialization)]
#![feature(control_flow_enum)]
#![feature(drain_filter)]
#![allow(rustc::potential_query_instability)]
#[macro_use]
extern crate tracing;
#[macro_use]
extern crate rustc_middle;
mod _match;
mod autoderef;
mod callee;
// Used by clippy;
pub mod cast;
mod check;
mod closure;
mod coercion;
mod demand;
mod diverges;
mod errors;
mod expectation;
mod expr;
// Used by clippy;
pub mod expr_use_visitor;
mod fallback;
mod fn_ctxt;
mod gather_locals;
mod generator_interior;
mod inherited;
mod intrinsicck;
mod mem_categorization;
mod method;
mod op;
mod pat;
mod place_op;
mod rvalue_scopes;
mod upvar;
mod writeback;
pub use diverges::Diverges;
pub use expectation::Expectation;
pub use fn_ctxt::*;
pub use inherited::{Inherited, InheritedBuilder};
use crate::check::check_fn;
use crate::coercion::DynamicCoerceMany;
use crate::gather_locals::GatherLocalsVisitor;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{struct_span_err, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::intravisit::Visitor;
use rustc_hir::{HirIdMap, Node};
use rustc_hir_analysis::astconv::AstConv;
use rustc_hir_analysis::check::check_abi;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::traits;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::config;
use rustc_session::Session;
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::Span;
#[macro_export]
macro_rules! type_error_struct {
($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({
let mut err = rustc_errors::struct_span_err!($session, $span, $code, $($message)*);
if $typ.references_error() {
err.downgrade_to_delayed_bug();
}
err
})
}
/// The type of a local binding, including the revealed type for anon types.
#[derive(Copy, Clone, Debug)]
pub struct LocalTy<'tcx> {
decl_ty: Ty<'tcx>,
revealed_ty: Ty<'tcx>,
}
#[derive(Copy, Clone)]
pub struct UnsafetyState {
pub def: hir::HirId,
pub unsafety: hir::Unsafety,
from_fn: bool,
}
impl UnsafetyState {
pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState {
UnsafetyState { def, unsafety, from_fn: true }
}
pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState {
use hir::BlockCheckMode;
match self.unsafety {
// If this unsafe, then if the outer function was already marked as
// unsafe we shouldn't attribute the unsafe'ness to the block. This
// way the block can be warned about instead of ignoring this
// extraneous block (functions are never warned about).
hir::Unsafety::Unsafe if self.from_fn => self,
unsafety => {
let (unsafety, def) = match blk.rules {
BlockCheckMode::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.hir_id),
BlockCheckMode::DefaultBlock => (unsafety, self.def),
};
UnsafetyState { def, unsafety, from_fn: false }
}
}
}
}
/// If this `DefId` is a "primary tables entry", returns
/// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
///
/// If this function returns `Some`, then `typeck_results(def_id)` will
/// succeed; if it returns `None`, then `typeck_results(def_id)` may or
/// may not succeed. In some cases where this function returns `None`
/// (notably closures), `typeck_results(def_id)` would wind up
/// redirecting to the owning function.
fn primary_body_of(
tcx: TyCtxt<'_>,
id: hir::HirId,
) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
match tcx.hir().get(id) {
Node::Item(item) => match item.kind {
hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => {
Some((body, Some(ty), None))
}
hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))),
_ => None,
},
Node::TraitItem(item) => match item.kind {
hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)),
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
Some((body, None, Some(sig)))
}
_ => None,
},
Node::ImplItem(item) => match item.kind {
hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)),
hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))),
_ => None,
},
Node::AnonConst(constant) => Some((constant.body, None, None)),
_ => None,
}
}
fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
// Closures' typeck results come from their outermost function,
// as they are part of the same "inference environment".
let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
if typeck_root_def_id != def_id {
return tcx.has_typeck_results(typeck_root_def_id);
}
if let Some(def_id) = def_id.as_local() {
let id = tcx.hir().local_def_id_to_hir_id(def_id);
primary_body_of(tcx, id).is_some()
} else {
false
}
}
fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDefId> {
&*tcx.typeck(def_id).used_trait_imports
}
fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
}
fn typeck_const_arg<'tcx>(
tcx: TyCtxt<'tcx>,
(did, param_did): (LocalDefId, DefId),
) -> &ty::TypeckResults<'tcx> {
let fallback = move || tcx.type_of(param_did);
typeck_with_fallback(tcx, did, fallback)
}
fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
if let Some(param_did) = tcx.opt_const_param_of(def_id) {
tcx.typeck_const_arg((def_id, param_did))
} else {
let fallback = move || tcx.type_of(def_id.to_def_id());
typeck_with_fallback(tcx, def_id, fallback)
}
}
/// Used only to get `TypeckResults` for type inference during error recovery.
/// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors.
fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
let fallback = move || {
let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id));
tcx.ty_error_with_message(span, "diagnostic only typeck table used")
};
typeck_with_fallback(tcx, def_id, fallback)
}
fn typeck_with_fallback<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
fallback: impl Fn() -> Ty<'tcx> + 'tcx,
) -> &'tcx ty::TypeckResults<'tcx> {
// Closures' typeck results come from their outermost function,
// as they are part of the same "inference environment".
let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
if typeck_root_def_id != def_id {
return tcx.typeck(typeck_root_def_id);
}
let id = tcx.hir().local_def_id_to_hir_id(def_id);
let span = tcx.hir().span(id);
// Figure out what primary body this item has.
let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| {
span_bug!(span, "can't type-check body of {:?}", def_id);
});
let body = tcx.hir().body(body_id);
let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
let param_env = tcx.param_env(def_id);
let mut fcx = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
let fn_sig = if rustc_hir_analysis::collect::get_infer_ret_ty(&decl.output).is_some() {
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
<dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
} else {
tcx.fn_sig(def_id)
};
check_abi(tcx, id, span, fn_sig.abi());
// Compute the function signature from point of view of inside the fn.
let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
let fn_sig = inh.normalize_associated_types_in(
body.value.span,
body_id.hir_id,
param_env,
fn_sig,
);
check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0
} else {
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
let expected_type = body_ty
.and_then(|ty| match ty.kind {
hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)),
_ => None,
})
.unwrap_or_else(|| match tcx.hir().get(id) {
Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) {
Node::Expr(&hir::Expr {
kind: hir::ExprKind::ConstBlock(ref anon_const),
..
}) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeInference,
span,
}),
Node::Ty(&hir::Ty {
kind: hir::TyKind::Typeof(ref anon_const), ..
}) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeInference,
span,
}),
Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
| Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
let operand_ty = asm
.operands
.iter()
.filter_map(|(op, _op_sp)| match op {
hir::InlineAsmOperand::Const { anon_const }
if anon_const.hir_id == id =>
{
// Inline assembly constants must be integers.
Some(fcx.next_int_var())
}
hir::InlineAsmOperand::SymFn { anon_const }
if anon_const.hir_id == id =>
{
Some(fcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::MiscVariable,
span,
}))
}
_ => None,
})
.next();
operand_ty.unwrap_or_else(fallback)
}
_ => fallback(),
},
_ => fallback(),
});
let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type);
fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
// Gather locals in statics (because of block expressions).
GatherLocalsVisitor::new(&fcx).visit_body(body);
fcx.check_expr_coercable_to_type(&body.value, expected_type, None);
fcx.write_ty(id, expected_type);
fcx
};
let fallback_has_occurred = fcx.type_inference_fallback();
// Even though coercion casts provide type hints, we check casts after fallback for
// backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
fcx.check_casts();
fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
// Closure and generator analysis may run after fallback
// because they don't constrain other type variables.
// Closure analysis only runs on closures. Therefore they only need to fulfill non-const predicates (as of now)
let prev_constness = fcx.param_env.constness();
fcx.param_env = fcx.param_env.without_const();
fcx.closure_analyze(body);
fcx.param_env = fcx.param_env.with_constness(prev_constness);
assert!(fcx.deferred_call_resolutions.borrow().is_empty());
// Before the generator analysis, temporary scopes shall be marked to provide more
// precise information on types to be captured.
fcx.resolve_rvalue_scopes(def_id.to_def_id());
fcx.resolve_generator_interiors(def_id.to_def_id());
for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
let ty = fcx.normalize_ty(span, ty);
fcx.require_type_is_sized(ty, span, code);
}
fcx.select_all_obligations_or_error();
if !fcx.infcx.is_tainted_by_errors() {
fcx.check_transmutes();
}
fcx.check_asms();
fcx.infcx.skip_region_resolution();
fcx.resolve_type_vars_in_body(body)
});
// Consistency check our TypeckResults instance can hold all ItemLocalIds
// it will need to hold.
assert_eq!(typeck_results.hir_owner, id.owner);
typeck_results
}
/// When `check_fn` is invoked on a generator (i.e., a body that
/// includes yield), it returns back some information about the yield
/// points.
struct GeneratorTypes<'tcx> {
/// Type of generator argument / values returned by `yield`.
resume_ty: Ty<'tcx>,
/// Type of value that is yielded.
yield_ty: Ty<'tcx>,
/// Types that are captured (see `GeneratorInterior` for more).
interior: Ty<'tcx>,
/// Indicates if the generator is movable or static (immovable).
movability: hir::Movability,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Needs {
MutPlace,
None,
}
impl Needs {
fn maybe_mut_place(m: hir::Mutability) -> Self {
match m {
hir::Mutability::Mut => Needs::MutPlace,
hir::Mutability::Not => Needs::None,
}
}
}
#[derive(Debug, Copy, Clone)]
pub enum PlaceOp {
Deref,
Index,
}
pub struct BreakableCtxt<'tcx> {
may_break: bool,
// this is `null` for loops where break with a value is illegal,
// such as `while`, `for`, and `while let`
coerce: Option<DynamicCoerceMany<'tcx>>,
}
pub struct EnclosingBreakables<'tcx> {
stack: Vec<BreakableCtxt<'tcx>>,
by_id: HirIdMap<usize>,
}
impl<'tcx> EnclosingBreakables<'tcx> {
fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> {
self.opt_find_breakable(target_id).unwrap_or_else(|| {
bug!("could not find enclosing breakable with id {}", target_id);
})
}
fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> {
match self.by_id.get(&target_id) {
Some(ix) => Some(&mut self.stack[*ix]),
None => None,
}
}
}
fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'_>, span: Span) {
struct_span_err!(
tcx.sess,
span,
E0533,
"expected unit struct, unit variant or constant, found {} `{}`",
res.descr(),
rustc_hir_pretty::qpath_to_string(qpath),
)
.emit();
}
/// Controls whether the arguments are tupled. This is used for the call
/// operator.
///
/// Tupling means that all call-side arguments are packed into a tuple and
/// passed as a single parameter. For example, if tupling is enabled, this
/// function:
/// ```
/// fn f(x: (isize, isize)) {}
/// ```
/// Can be called as:
/// ```ignore UNSOLVED (can this be done in user code?)
/// # fn f(x: (isize, isize)) {}
/// f(1, 2);
/// ```
/// Instead of:
/// ```
/// # fn f(x: (isize, isize)) {}
/// f((1, 2));
/// ```
#[derive(Clone, Eq, PartialEq)]
enum TupleArgumentsFlag {
DontTupleArguments,
TupleArguments,
}
fn fatally_break_rust(sess: &Session) {
let handler = sess.diagnostic();
handler.span_bug_no_panic(
MultiSpan::new(),
"It looks like you're trying to break rust; would you like some ICE?",
);
handler.note_without_error("the compiler expectedly panicked. this is a feature.");
handler.note_without_error(
"we would appreciate a joke overview: \
https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
);
handler.note_without_error(&format!(
"rustc {} running on {}",
option_env!("CFG_VERSION").unwrap_or("unknown_version"),
config::host_triple(),
));
}
fn has_expected_num_generic_args<'tcx>(
tcx: TyCtxt<'tcx>,
trait_did: Option<DefId>,
expected: usize,
) -> bool {
trait_did.map_or(true, |trait_did| {
let generics = tcx.generics_of(trait_did);
generics.count() == expected + if generics.has_self { 1 } else { 0 }
})
}
pub fn provide(providers: &mut Providers) {
method::provide(providers);
*providers = Providers {
typeck_item_bodies,
typeck_const_arg,
typeck,
diagnostic_only_typeck,
has_typeck_results,
used_trait_imports,
..*providers
};
}

View file

@ -1,10 +1,10 @@
use super::{probe, MethodCallee};
use crate::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall};
use crate::check::{callee, FnCtxt};
use crate::{callee, FnCtxt};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::GenericArg;
use rustc_hir_analysis::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall};
use rustc_infer::infer::{self, InferOk};
use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};

View file

@ -10,14 +10,14 @@
pub use self::suggest::SelfSource;
pub use self::MethodError::*;
use crate::check::{Expectation, FnCtxt};
use crate::ObligationCause;
use crate::{Expectation, FnCtxt};
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, Diagnostic};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Namespace};
use rustc_hir::def_id::DefId;
use rustc_infer::infer::{self, InferOk};
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TypeVisitable};
use rustc_span::symbol::Ident;

View file

@ -1,3 +1,7 @@
use crate::{
method::probe::{self, Pick},
FnCtxt,
};
use hir::def_id::DefId;
use hir::HirId;
use hir::ItemKind;
@ -12,11 +16,6 @@
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
use crate::check::{
method::probe::{self, Pick},
FnCtxt,
};
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(super) fn lint_dot_call_from_2018(
&self,

View file

@ -3,14 +3,12 @@
use super::MethodError;
use super::NoMatchData;
use crate::check::FnCtxt;
use crate::errors::MethodCallOnUnknownType;
use crate::hir::def::DefKind;
use crate::hir::def_id::DefId;
use crate::FnCtxt;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def::Namespace;
use rustc_infer::infer::canonical::OriginalQueryValues;
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
@ -23,6 +21,7 @@
use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitable};
use rustc_middle::ty::{InternalSubsts, SubstsRef};
use rustc_session::lint;
use rustc_span::def_id::DefId;
use rustc_span::def_id::LocalDefId;
use rustc_span::lev_distance::{
find_best_match_for_name_with_substrings, lev_distance_with_substrings,

View file

@ -1,8 +1,8 @@
//! Give useful errors and suggestions to users when an item can't be
//! found or is otherwise invalid.
use crate::check::FnCtxt;
use crate::errors;
use crate::FnCtxt;
use rustc_ast::ast::Mutability;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{

View file

@ -2,7 +2,7 @@
use super::method::MethodCallee;
use super::{has_expected_num_generic_args, FnCtxt};
use crate::check::Expectation;
use crate::Expectation;
use rustc_ast as ast;
use rustc_errors::{self, struct_span_err, Applicability, Diagnostic};
use rustc_hir as hir;

View file

@ -1,6 +1,5 @@
use crate::check::FnCtxt;
use crate::FnCtxt;
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,

View file

@ -1,5 +1,5 @@
use crate::check::method::MethodCallee;
use crate::check::{has_expected_num_generic_args, FnCtxt, PlaceOp};
use crate::method::MethodCallee;
use crate::{has_expected_num_generic_args, FnCtxt, PlaceOp};
use rustc_ast as ast;
use rustc_errors::Applicability;
use rustc_hir as hir;

View file

@ -2,7 +2,7 @@
// unresolved type variables and replaces "ty_var" types with their
// substitutions.
use crate::check::FnCtxt;
use crate::FnCtxt;
use hir::def_id::LocalDefId;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::ErrorGuaranteed;

View file

@ -38,6 +38,7 @@ rustc_mir_transform = { path = "../rustc_mir_transform" }
rustc_monomorphize = { path = "../rustc_monomorphize" }
rustc_passes = { path = "../rustc_passes" }
rustc_hir_analysis = { path = "../rustc_hir_analysis" }
rustc_hir_typeck = { path = "../rustc_hir_typeck" }
rustc_lint = { path = "../rustc_lint" }
rustc_errors = { path = "../rustc_errors" }
rustc_plugin_impl = { path = "../rustc_plugin_impl" }

View file

@ -736,6 +736,7 @@ pub fn prepare_outputs(
rustc_monomorphize::provide(providers);
rustc_privacy::provide(providers);
rustc_hir_analysis::provide(providers);
rustc_hir_typeck::provide(providers);
ty::provide(providers);
traits::provide(providers);
rustc_passes::provide(providers);