diff --git a/pyrefly/lib/alt/solve.rs b/pyrefly/lib/alt/solve.rs index 48e83d40a..e4696ffb6 100644 --- a/pyrefly/lib/alt/solve.rs +++ b/pyrefly/lib/alt/solve.rs @@ -4028,6 +4028,25 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> { "Type variable bounds and constraints must be concrete".to_owned(), ); } + if type_form_context == TypeFormContext::TypeArgumentForType { + if let Some(cls) = match &ty { + Type::ClassType(cls) | Type::SelfType(cls) => Some(cls.class_object().clone()), + Type::ClassDef(cls) => Some(cls.clone()), + _ => None, + } { + if self.get_metadata_for_class(&cls).is_new_type() { + return self.error( + errors, + range, + ErrorInfo::Kind(ErrorKind::InvalidAnnotation), + format!( + "NewType `{}` is not a class and cannot be used with `type` or `Type`", + cls.name() + ), + ); + } + } + } ty } diff --git a/pyrefly/lib/test/new_type.rs b/pyrefly/lib/test/new_type.rs index 2b87d95c3..a740d26ca 100644 --- a/pyrefly/lib/test/new_type.rs +++ b/pyrefly/lib/test/new_type.rs @@ -136,6 +136,22 @@ y: type[Any] = Foo # E: `type[Foo]` is not assignable to `type[Any]` "#, ); +testcase!( + test_new_type_type_argument, + r#" +from typing import NewType, Type + +Thing = NewType("Thing", int) +ThingType = type[Thing] # E: NewType `Thing` is not a class and cannot be used with `type` or `Type` +OtherThingType = Type[Thing] # E: NewType `Thing` is not a class and cannot be used with `type` or `Type` + +mapping: dict[int, ThingType] = {1: Thing} # E: `dict[int, type[Thing]]` is not assignable to `dict[int, type[Unknown]]` + +def func(x: ThingType) -> None: ... +func(Thing) # E: Argument `type[Thing]` is not assignable to parameter `x` with type `type[Unknown]` in function `func` + "#, +); + testcase!( test_new_type_runtime_attrs, r#"