mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-04 19:29:07 +00:00
Merge #11920
11920: Consider types of const generics r=flodiebold a=HKalbasi fix #11913 We should emit type_mismatch in const generics, probably after #7434. Currently they will lead to a misleading, time of use type error (like the added test). Co-authored-by: hkalbasi <hamidrezakalbasi@protonmail.com>
This commit is contained in:
commit
b8ed4a388c
@ -154,6 +154,10 @@ impl TyBuilder<()> {
|
|||||||
TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner)
|
TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn usize() -> Ty {
|
||||||
|
TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)).intern(Interner)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn fn_ptr(sig: CallableSig) -> Ty {
|
pub fn fn_ptr(sig: CallableSig) -> Ty {
|
||||||
TyKind::Function(sig.to_fn_ptr()).intern(Interner)
|
TyKind::Function(sig.to_fn_ptr()).intern(Interner)
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ use stdx::never;
|
|||||||
use crate::{
|
use crate::{
|
||||||
db::HirDatabase, infer::InferenceContext, lower::ParamLoweringMode, to_placeholder_idx,
|
db::HirDatabase, infer::InferenceContext, lower::ParamLoweringMode, to_placeholder_idx,
|
||||||
utils::Generics, Const, ConstData, ConstValue, GenericArg, InferenceResult, Interner, Ty,
|
utils::Generics, Const, ConstData, ConstValue, GenericArg, InferenceResult, Interner, Ty,
|
||||||
TyKind,
|
TyBuilder, TyKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Extension trait for [`Const`]
|
/// Extension trait for [`Const`]
|
||||||
@ -401,23 +401,22 @@ pub fn unknown_const(ty: Ty) -> Const {
|
|||||||
.intern(Interner)
|
.intern(Interner)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unknown_const_usize() -> Const {
|
|
||||||
unknown_const(TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)).intern(Interner))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unknown_const_as_generic(ty: Ty) -> GenericArg {
|
pub fn unknown_const_as_generic(ty: Ty) -> GenericArg {
|
||||||
GenericArgData::Const(unknown_const(ty)).intern(Interner)
|
GenericArgData::Const(unknown_const(ty)).intern(Interner)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Interns a constant scalar with the given type
|
||||||
|
pub fn intern_scalar_const(value: ConstScalar, ty: Ty) -> Const {
|
||||||
|
ConstData { ty, value: ConstValue::Concrete(chalk_ir::ConcreteConst { interned: value }) }
|
||||||
|
.intern(Interner)
|
||||||
|
}
|
||||||
|
|
||||||
/// Interns a possibly-unknown target usize
|
/// Interns a possibly-unknown target usize
|
||||||
pub fn usize_const(value: Option<u64>) -> Const {
|
pub fn usize_const(value: Option<u64>) -> Const {
|
||||||
ConstData {
|
intern_scalar_const(
|
||||||
ty: TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)).intern(Interner),
|
value.map(ConstScalar::Usize).unwrap_or(ConstScalar::Unknown),
|
||||||
value: ConstValue::Concrete(chalk_ir::ConcreteConst {
|
TyBuilder::usize(),
|
||||||
interned: value.map(ConstScalar::Usize).unwrap_or(ConstScalar::Unknown),
|
)
|
||||||
}),
|
|
||||||
}
|
|
||||||
.intern(Interner)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn const_eval_recover(
|
pub(crate) fn const_eval_recover(
|
||||||
|
@ -1129,10 +1129,11 @@ impl<'a> InferenceContext<'a> {
|
|||||||
arg,
|
arg,
|
||||||
self,
|
self,
|
||||||
|this, type_ref| this.make_ty(type_ref),
|
|this, type_ref| this.make_ty(type_ref),
|
||||||
|this, c| {
|
|this, c, ty| {
|
||||||
const_or_path_to_chalk(
|
const_or_path_to_chalk(
|
||||||
this.db,
|
this.db,
|
||||||
&this.resolver,
|
&this.resolver,
|
||||||
|
ty,
|
||||||
c,
|
c,
|
||||||
ParamLoweringMode::Placeholder,
|
ParamLoweringMode::Placeholder,
|
||||||
|| generics(this.db.upcast(), (&this.resolver).generic_def().unwrap()),
|
|| generics(this.db.upcast(), (&this.resolver).generic_def().unwrap()),
|
||||||
|
@ -35,17 +35,13 @@ use std::sync::Arc;
|
|||||||
use chalk_ir::{
|
use chalk_ir::{
|
||||||
fold::{Fold, Shift},
|
fold::{Fold, Shift},
|
||||||
interner::HasInterner,
|
interner::HasInterner,
|
||||||
NoSolution, UintTy,
|
NoSolution,
|
||||||
};
|
|
||||||
use hir_def::{
|
|
||||||
expr::ExprId,
|
|
||||||
type_ref::{ConstScalar, Rawness},
|
|
||||||
TypeOrConstParamId,
|
|
||||||
};
|
};
|
||||||
|
use hir_def::{expr::ExprId, type_ref::Rawness, TypeOrConstParamId};
|
||||||
use itertools::Either;
|
use itertools::Either;
|
||||||
use utils::Generics;
|
use utils::Generics;
|
||||||
|
|
||||||
use crate::{db::HirDatabase, utils::generics};
|
use crate::{consteval::unknown_const, db::HirDatabase, utils::generics};
|
||||||
|
|
||||||
pub use autoderef::autoderef;
|
pub use autoderef::autoderef;
|
||||||
pub use builder::{ParamKind, TyBuilder};
|
pub use builder::{ParamKind, TyBuilder};
|
||||||
@ -303,17 +299,6 @@ pub fn static_lifetime() -> Lifetime {
|
|||||||
LifetimeData::Static.intern(Interner)
|
LifetimeData::Static.intern(Interner)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dummy_usize_const() -> Const {
|
|
||||||
let usize_ty = chalk_ir::TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner);
|
|
||||||
chalk_ir::ConstData {
|
|
||||||
ty: usize_ty,
|
|
||||||
value: chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst {
|
|
||||||
interned: ConstScalar::Unknown,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
.intern(Interner)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + Fold<Interner>>(
|
pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + Fold<Interner>>(
|
||||||
t: T,
|
t: T,
|
||||||
for_ty: impl FnMut(BoundVar, DebruijnIndex) -> Ty,
|
for_ty: impl FnMut(BoundVar, DebruijnIndex) -> Ty,
|
||||||
@ -476,27 +461,27 @@ where
|
|||||||
|
|
||||||
fn fold_inference_const(
|
fn fold_inference_const(
|
||||||
&mut self,
|
&mut self,
|
||||||
_ty: Ty,
|
ty: Ty,
|
||||||
_var: InferenceVar,
|
_var: InferenceVar,
|
||||||
_outer_binder: DebruijnIndex,
|
_outer_binder: DebruijnIndex,
|
||||||
) -> Fallible<Const> {
|
) -> Fallible<Const> {
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
Err(NoSolution)
|
Err(NoSolution)
|
||||||
} else {
|
} else {
|
||||||
Ok(dummy_usize_const())
|
Ok(unknown_const(ty))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_free_var_const(
|
fn fold_free_var_const(
|
||||||
&mut self,
|
&mut self,
|
||||||
_ty: Ty,
|
ty: Ty,
|
||||||
_bound_var: BoundVar,
|
_bound_var: BoundVar,
|
||||||
_outer_binder: DebruijnIndex,
|
_outer_binder: DebruijnIndex,
|
||||||
) -> Fallible<Const> {
|
) -> Fallible<Const> {
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
Err(NoSolution)
|
Err(NoSolution)
|
||||||
} else {
|
} else {
|
||||||
Ok(dummy_usize_const())
|
Ok(unknown_const(ty))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,11 +37,12 @@ use smallvec::SmallVec;
|
|||||||
use stdx::{impl_from, never};
|
use stdx::{impl_from, never};
|
||||||
use syntax::{ast, SmolStr};
|
use syntax::{ast, SmolStr};
|
||||||
|
|
||||||
use crate::consteval::{path_to_const, unknown_const_as_generic, unknown_const_usize, usize_const};
|
use crate::consteval::{
|
||||||
|
intern_scalar_const, path_to_const, unknown_const, unknown_const_as_generic,
|
||||||
|
};
|
||||||
use crate::utils::Generics;
|
use crate::utils::Generics;
|
||||||
use crate::{all_super_traits, make_binders, Const, GenericArgData, ParamKind};
|
use crate::{all_super_traits, make_binders, Const, GenericArgData, ParamKind};
|
||||||
use crate::{
|
use crate::{
|
||||||
consteval,
|
|
||||||
db::HirDatabase,
|
db::HirDatabase,
|
||||||
mapping::ToChalk,
|
mapping::ToChalk,
|
||||||
static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
|
static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
|
||||||
@ -202,6 +203,7 @@ impl<'a> TyLoweringContext<'a> {
|
|||||||
let const_len = const_or_path_to_chalk(
|
let const_len = const_or_path_to_chalk(
|
||||||
self.db,
|
self.db,
|
||||||
self.resolver,
|
self.resolver,
|
||||||
|
TyBuilder::usize(),
|
||||||
len,
|
len,
|
||||||
self.type_param_mode,
|
self.type_param_mode,
|
||||||
|| self.generics(),
|
|| self.generics(),
|
||||||
@ -677,12 +679,13 @@ impl<'a> TyLoweringContext<'a> {
|
|||||||
parent_params + self_params + type_params + const_params + impl_trait_params;
|
parent_params + self_params + type_params + const_params + impl_trait_params;
|
||||||
|
|
||||||
let ty_error = GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner);
|
let ty_error = GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner);
|
||||||
let const_error = GenericArgData::Const(consteval::usize_const(None)).intern(Interner);
|
|
||||||
|
|
||||||
for (_, data) in def_generics.iter().take(parent_params) {
|
for eid in def_generics.iter_id().take(parent_params) {
|
||||||
match data {
|
match eid {
|
||||||
TypeOrConstParamData::TypeParamData(_) => substs.push(ty_error.clone()),
|
Either::Left(_) => substs.push(ty_error.clone()),
|
||||||
TypeOrConstParamData::ConstParamData(_) => substs.push(const_error.clone()),
|
Either::Right(x) => {
|
||||||
|
substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -722,10 +725,11 @@ impl<'a> TyLoweringContext<'a> {
|
|||||||
arg,
|
arg,
|
||||||
&mut (),
|
&mut (),
|
||||||
|_, type_ref| self.lower_ty(type_ref),
|
|_, type_ref| self.lower_ty(type_ref),
|
||||||
|_, c| {
|
|_, c, ty| {
|
||||||
const_or_path_to_chalk(
|
const_or_path_to_chalk(
|
||||||
self.db,
|
self.db,
|
||||||
&self.resolver,
|
&self.resolver,
|
||||||
|
ty,
|
||||||
c,
|
c,
|
||||||
self.type_param_mode,
|
self.type_param_mode,
|
||||||
|| self.generics(),
|
|| self.generics(),
|
||||||
@ -759,10 +763,12 @@ impl<'a> TyLoweringContext<'a> {
|
|||||||
|
|
||||||
// add placeholders for args that were not provided
|
// add placeholders for args that were not provided
|
||||||
// FIXME: emit diagnostics in contexts where this is not allowed
|
// FIXME: emit diagnostics in contexts where this is not allowed
|
||||||
for (_, data) in def_generics.iter().skip(substs.len()) {
|
for eid in def_generics.iter_id().skip(substs.len()) {
|
||||||
match data {
|
match eid {
|
||||||
TypeOrConstParamData::TypeParamData(_) => substs.push(ty_error.clone()),
|
Either::Left(_) => substs.push(ty_error.clone()),
|
||||||
TypeOrConstParamData::ConstParamData(_) => substs.push(const_error.clone()),
|
Either::Right(x) => {
|
||||||
|
substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert_eq!(substs.len(), total_len);
|
assert_eq!(substs.len(), total_len);
|
||||||
@ -1642,7 +1648,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
|
|||||||
arg: &'a GenericArg,
|
arg: &'a GenericArg,
|
||||||
this: &mut T,
|
this: &mut T,
|
||||||
for_type: impl FnOnce(&mut T, &TypeRef) -> Ty + 'a,
|
for_type: impl FnOnce(&mut T, &TypeRef) -> Ty + 'a,
|
||||||
for_const: impl FnOnce(&mut T, &ConstScalarOrPath) -> Const + 'a,
|
for_const: impl FnOnce(&mut T, &ConstScalarOrPath, Ty) -> Const + 'a,
|
||||||
) -> Option<crate::GenericArg> {
|
) -> Option<crate::GenericArg> {
|
||||||
let kind = match kind_id {
|
let kind = match kind_id {
|
||||||
Either::Left(_) => ParamKind::Type,
|
Either::Left(_) => ParamKind::Type,
|
||||||
@ -1656,13 +1662,13 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
|
|||||||
let ty = for_type(this, type_ref);
|
let ty = for_type(this, type_ref);
|
||||||
GenericArgData::Ty(ty).intern(Interner)
|
GenericArgData::Ty(ty).intern(Interner)
|
||||||
}
|
}
|
||||||
(GenericArg::Const(c), ParamKind::Const(_)) => {
|
(GenericArg::Const(c), ParamKind::Const(c_ty)) => {
|
||||||
GenericArgData::Const(for_const(this, c)).intern(Interner)
|
GenericArgData::Const(for_const(this, c, c_ty)).intern(Interner)
|
||||||
}
|
}
|
||||||
(GenericArg::Const(_), ParamKind::Type) => {
|
(GenericArg::Const(_), ParamKind::Type) => {
|
||||||
GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
|
GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
|
||||||
}
|
}
|
||||||
(GenericArg::Type(t), ParamKind::Const(ty)) => {
|
(GenericArg::Type(t), ParamKind::Const(c_ty)) => {
|
||||||
// We want to recover simple idents, which parser detects them
|
// We want to recover simple idents, which parser detects them
|
||||||
// as types. Maybe here is not the best place to do it, but
|
// as types. Maybe here is not the best place to do it, but
|
||||||
// it works.
|
// it works.
|
||||||
@ -1671,11 +1677,13 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
|
|||||||
if p.kind == PathKind::Plain {
|
if p.kind == PathKind::Plain {
|
||||||
if let [n] = p.segments() {
|
if let [n] = p.segments() {
|
||||||
let c = ConstScalarOrPath::Path(n.clone());
|
let c = ConstScalarOrPath::Path(n.clone());
|
||||||
return Some(GenericArgData::Const(for_const(this, &c)).intern(Interner));
|
return Some(
|
||||||
|
GenericArgData::Const(for_const(this, &c, c_ty)).intern(Interner),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unknown_const_as_generic(ty)
|
unknown_const_as_generic(c_ty)
|
||||||
}
|
}
|
||||||
(GenericArg::Lifetime(_), _) => return None,
|
(GenericArg::Lifetime(_), _) => return None,
|
||||||
})
|
})
|
||||||
@ -1684,17 +1692,18 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
|
|||||||
pub(crate) fn const_or_path_to_chalk(
|
pub(crate) fn const_or_path_to_chalk(
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
resolver: &Resolver,
|
resolver: &Resolver,
|
||||||
|
expected_ty: Ty,
|
||||||
value: &ConstScalarOrPath,
|
value: &ConstScalarOrPath,
|
||||||
mode: ParamLoweringMode,
|
mode: ParamLoweringMode,
|
||||||
args: impl FnOnce() -> Generics,
|
args: impl FnOnce() -> Generics,
|
||||||
debruijn: DebruijnIndex,
|
debruijn: DebruijnIndex,
|
||||||
) -> Const {
|
) -> Const {
|
||||||
match value {
|
match value {
|
||||||
ConstScalarOrPath::Scalar(s) => usize_const(s.as_usize()),
|
ConstScalarOrPath::Scalar(s) => intern_scalar_const(s.clone(), expected_ty),
|
||||||
ConstScalarOrPath::Path(n) => {
|
ConstScalarOrPath::Path(n) => {
|
||||||
let path = ModPath::from_segments(PathKind::Plain, Some(n.clone()));
|
let path = ModPath::from_segments(PathKind::Plain, Some(n.clone()));
|
||||||
path_to_const(db, resolver, &path, mode, args, debruijn)
|
path_to_const(db, resolver, &path, mode, args, debruijn)
|
||||||
.unwrap_or_else(|| unknown_const_usize())
|
.unwrap_or_else(|| unknown_const(expected_ty))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1716,7 +1725,7 @@ fn fallback_bound_vars<T: Fold<Interner> + HasInterner<Interner = Interner>>(
|
|||||||
},
|
},
|
||||||
|ty, bound, binders| {
|
|ty, bound, binders| {
|
||||||
if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
|
if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
|
||||||
consteval::unknown_const(ty.clone())
|
unknown_const(ty.clone())
|
||||||
} else {
|
} else {
|
||||||
bound.shifted_in_from(binders).to_const(Interner, ty)
|
bound.shifted_in_from(binders).to_const(Interner, ty)
|
||||||
}
|
}
|
||||||
|
@ -316,6 +316,38 @@ fn div(x: i32, y: i32) -> Option<i32> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn const_generic_type_mismatch() {
|
||||||
|
check_diagnostics(
|
||||||
|
r#"
|
||||||
|
pub struct Rate<const N: u32>;
|
||||||
|
fn f<const N: u64>() -> Rate<N> { // FIXME: add some error
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
fn run(t: Rate<5>) {
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
run(f()) // FIXME: remove this error
|
||||||
|
//^^^ error: expected Rate<5>, found Rate<_>
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn const_generic_unknown() {
|
||||||
|
check_diagnostics(
|
||||||
|
r#"
|
||||||
|
pub struct Rate<T, const NOM: u32, const DENOM: u32>(T);
|
||||||
|
fn run(t: Rate<u32, 1, 1>) {
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
run(Rate::<_, _, _>(5));
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_wrap_return_type_option_tails() {
|
fn test_wrap_return_type_option_tails() {
|
||||||
check_fix(
|
check_fix(
|
||||||
|
Loading…
Reference in New Issue
Block a user