mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-06 07:34:45 +01:00
Basic support for incomplete types. (#3302)
Incomplete types may be nested within other types; for example, a tuple type might have an incomplete type as an element. Handle such cases by walking through nested incomplete types when completing a type. This is done non-recursively in case a very complex type is formed. Types are generally no longer completed at the point where they're formed. Instead, we attempt to complete a type when it is used in a context that requires a complete type, and diagnose if the type cannot be completed at that point. This will be necessary for classes, which can become complete after their first use, and helps tease out bugs where a type completeness check is missing.
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
// AUTOUPDATE
|
||||
|
||||
class Class;
|
||||
|
||||
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE+6]]:17: ERROR: Variable has incomplete type `Class`.
|
||||
// CHECK:STDERR: var global_var: Class;
|
||||
// CHECK:STDERR: ^
|
||||
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE-5]]:1: Class was forward declared here.
|
||||
// CHECK:STDERR: class Class;
|
||||
// CHECK:STDERR: ^
|
||||
var global_var: Class;
|
||||
|
||||
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE+6]]:24: ERROR: Function returns incomplete type `Class`.
|
||||
// CHECK:STDERR: fn ConvertFromStruct() -> Class { return {}; }
|
||||
// CHECK:STDERR: ^
|
||||
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE-13]]:1: Class was forward declared here.
|
||||
// CHECK:STDERR: class Class;
|
||||
// CHECK:STDERR: ^
|
||||
fn ConvertFromStruct() -> Class { return {}; }
|
||||
|
||||
// TODO: Once the `->` operator is supported:
|
||||
// TODO: fn G(p: Class*) -> i32 {
|
||||
// TODO: return p->n;
|
||||
// TODO: }
|
||||
|
||||
fn MemberAccess(p: Class*) -> i32 {
|
||||
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE+9]]:11: ERROR: Invalid use of incomplete type `Class`.
|
||||
// CHECK:STDERR: return (*p).n;
|
||||
// CHECK:STDERR: ^
|
||||
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE-27]]:1: Class was forward declared here.
|
||||
// CHECK:STDERR: class Class;
|
||||
// CHECK:STDERR: ^
|
||||
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE+3]]:14: ERROR: Type `Class` does not support qualified expressions.
|
||||
// CHECK:STDERR: return (*p).n;
|
||||
// CHECK:STDERR: ^
|
||||
return (*p).n;
|
||||
}
|
||||
|
||||
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE+6]]:20: ERROR: Function returns incomplete type `Class`.
|
||||
// CHECK:STDERR: fn Copy(p: Class*) -> Class {
|
||||
// CHECK:STDERR: ^
|
||||
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE-39]]:1: Class was forward declared here.
|
||||
// CHECK:STDERR: class Class;
|
||||
// CHECK:STDERR: ^
|
||||
fn Copy(p: Class*) -> Class {
|
||||
return *p;
|
||||
}
|
||||
|
||||
fn Let(p: Class*) {
|
||||
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE+6]]:10: ERROR: `let` binding has incomplete type `Class`.
|
||||
// CHECK:STDERR: let c: Class = *p;
|
||||
// CHECK:STDERR: ^
|
||||
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE-50]]:1: Class was forward declared here.
|
||||
// CHECK:STDERR: class Class;
|
||||
// CHECK:STDERR: ^
|
||||
let c: Class = *p;
|
||||
}
|
||||
|
||||
fn TakeIncomplete(c: Class);
|
||||
|
||||
// TODO: We should allow this, and only reject calls to the function.
|
||||
//
|
||||
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE+6]]:23: ERROR: Function returns incomplete type `Class`.
|
||||
// CHECK:STDERR: fn ReturnIncomplete() -> Class;
|
||||
// CHECK:STDERR: ^
|
||||
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE-63]]:1: Class was forward declared here.
|
||||
// CHECK:STDERR: class Class;
|
||||
// CHECK:STDERR: ^
|
||||
fn ReturnIncomplete() -> Class;
|
||||
|
||||
fn CallTakeIncomplete(p: Class*) {
|
||||
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE+9]]:17: ERROR: Forming value of incomplete type `Class`.
|
||||
// CHECK:STDERR: TakeIncomplete(*p);
|
||||
// CHECK:STDERR: ^
|
||||
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE-72]]:1: Class was forward declared here.
|
||||
// CHECK:STDERR: class Class;
|
||||
// CHECK:STDERR: ^
|
||||
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE-19]]:1: Initializing parameter 1 of function declared here.
|
||||
// CHECK:STDERR: fn TakeIncomplete(c: Class);
|
||||
// CHECK:STDERR: ^
|
||||
TakeIncomplete(*p);
|
||||
|
||||
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE+9]]:17: ERROR: Forming value of incomplete type `Class`.
|
||||
// CHECK:STDERR: TakeIncomplete({});
|
||||
// CHECK:STDERR: ^
|
||||
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE-83]]:1: Class was forward declared here.
|
||||
// CHECK:STDERR: class Class;
|
||||
// CHECK:STDERR: ^
|
||||
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE-30]]:1: Initializing parameter 1 of function declared here.
|
||||
// CHECK:STDERR: fn TakeIncomplete(c: Class);
|
||||
// CHECK:STDERR: ^
|
||||
TakeIncomplete({});
|
||||
}
|
||||
|
||||
fn CallReturnIncomplete() {
|
||||
ReturnIncomplete();
|
||||
}
|
||||
|
||||
// CHECK:STDOUT: file "fail_incomplete.carbon" {
|
||||
// CHECK:STDOUT: %Class: type = class_declaration @Class
|
||||
// CHECK:STDOUT: %Class.ref: type = name_reference "Class", %Class
|
||||
// CHECK:STDOUT: %global_var: ref <error> = var "global_var"
|
||||
// CHECK:STDOUT: %ConvertFromStruct: <function> = fn_decl @ConvertFromStruct
|
||||
// CHECK:STDOUT: %MemberAccess: <function> = fn_decl @MemberAccess
|
||||
// CHECK:STDOUT: %Copy: <function> = fn_decl @Copy
|
||||
// CHECK:STDOUT: %Let: <function> = fn_decl @Let
|
||||
// CHECK:STDOUT: %TakeIncomplete: <function> = fn_decl @TakeIncomplete
|
||||
// CHECK:STDOUT: %ReturnIncomplete: <function> = fn_decl @ReturnIncomplete
|
||||
// CHECK:STDOUT: %CallTakeIncomplete: <function> = fn_decl @CallTakeIncomplete
|
||||
// CHECK:STDOUT: %CallReturnIncomplete: <function> = fn_decl @CallReturnIncomplete
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @Class;
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @ConvertFromStruct() -> <error> {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %.loc23_43.1: type = struct_type {}
|
||||
// CHECK:STDOUT: %.loc23_43.2: {} = struct_literal ()
|
||||
// CHECK:STDOUT: return <error>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @MemberAccess(%p: Class*) -> i32 {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %p.ref: Class* = name_reference "p", %p
|
||||
// CHECK:STDOUT: %.loc40: ref Class = dereference %p.ref
|
||||
// CHECK:STDOUT: return <error>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Copy(%p: Class*) -> <error> {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %p.ref: Class* = name_reference "p", %p
|
||||
// CHECK:STDOUT: %.loc50: ref Class = dereference %p.ref
|
||||
// CHECK:STDOUT: return <error>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Let(%p: Class*) {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Class.ref: type = name_reference "Class", package.%Class
|
||||
// CHECK:STDOUT: %p.ref: Class* = name_reference "p", %p
|
||||
// CHECK:STDOUT: %.loc60: ref Class = dereference %p.ref
|
||||
// CHECK:STDOUT: %c: <error> = bind_name "c", <error>
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @TakeIncomplete(%c: Class);
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @ReturnIncomplete() -> <error>;
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @CallTakeIncomplete(%p: Class*) {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %TakeIncomplete.ref.loc85: <function> = name_reference "TakeIncomplete", package.%TakeIncomplete
|
||||
// CHECK:STDOUT: %p.ref: Class* = name_reference "p", %p
|
||||
// CHECK:STDOUT: %.loc85_18: ref Class = dereference %p.ref
|
||||
// CHECK:STDOUT: %.loc85_17: type = tuple_type ()
|
||||
// CHECK:STDOUT: %TakeIncomplete.ref.loc96: <function> = name_reference "TakeIncomplete", package.%TakeIncomplete
|
||||
// CHECK:STDOUT: %.loc96: {} = struct_literal ()
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @CallReturnIncomplete() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %ReturnIncomplete.ref: <function> = name_reference "ReturnIncomplete", package.%ReturnIncomplete
|
||||
// CHECK:STDOUT: %.loc100: init <error> = call %ReturnIncomplete.ref()
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
Reference in New Issue
Block a user