1# coding=utf-8 2# 3# Copyright (c) 2025 Huawei Device Co., Ltd. 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16from dataclasses import dataclass, field 17from enum import Enum 18from typing import TYPE_CHECKING 19 20from typing_extensions import override 21 22from taihe.utils.diagnostics import DiagError, DiagFatalError, DiagNote, DiagWarn 23from taihe.utils.sources import SourceLocation 24 25if TYPE_CHECKING: 26 from taihe.semantics.declarations import ( 27 EnumDecl, 28 EnumItemDecl, 29 IfaceDecl, 30 NamedDecl, 31 PackageDecl, 32 PackageLevelDecl, 33 Type, 34 TypeDecl, 35 TypeRefDecl, 36 ) 37 38 39@dataclass 40class DeclRedefNote(DiagNote): 41 prev: "NamedDecl" 42 43 def __init__(self, prev: "NamedDecl"): 44 super().__init__(loc=prev.loc) 45 self.prev = prev 46 47 @override 48 def describe(self) -> str: 49 return "previously defined here" 50 51 52@dataclass 53class DeclRedefError(DiagError): 54 prev: "NamedDecl" 55 current: "NamedDecl" 56 57 def __init__(self, prev: "NamedDecl", current: "NamedDecl"): 58 super().__init__(loc=current.loc) 59 self.prev = prev 60 self.current = current 61 62 @override 63 def describe(self) -> str: 64 return f"redefinition of {self.current.description}" 65 66 @override 67 def notes(self): 68 if self.prev.loc: 69 yield DeclRedefNote(self.prev) 70 71 72@dataclass 73class IDLSyntaxError(DiagError): 74 token: str 75 76 @override 77 def describe(self) -> str: 78 return f"unexpected {self.token!r}" 79 80 81@dataclass 82class PackageNotExistError(DiagError): 83 name: str 84 85 @override 86 def describe(self) -> str: 87 return f"package {self.name!r} not exist" 88 89 90@dataclass 91class DeclNotExistError(DiagError): 92 name: str 93 94 @override 95 def describe(self) -> str: 96 return f"declaration {self.name!r} not exist" 97 98 99@dataclass 100class NotATypeError(DiagError): 101 name: str 102 103 @override 104 def describe(self) -> str: 105 return f"{self.name!r} is not a type name" 106 107 108@dataclass 109class DeclarationNotInScopeError(DiagError): 110 name: str 111 112 @override 113 def describe(self) -> str: 114 return ( 115 f"declaration name {self.name!r} is not declared or imported in this scope" 116 ) 117 118 119@dataclass 120class PackageNotInScopeError(DiagError): 121 name: str 122 123 @override 124 def describe(self) -> str: 125 return f"package name {self.name!r} is not imported in this scope" 126 127 128@dataclass 129class GenericArgumentsError(DiagError): 130 name: str 131 132 @override 133 def describe(self) -> str: 134 return f"Invalid generic arguments in {self.name!r}" 135 136 137@dataclass 138class SymbolConflictWithNamespaceNote(DiagNote): 139 name: str 140 package: "PackageDecl" 141 142 def __init__( 143 self, 144 name: str, 145 package: "PackageDecl", 146 ): 147 super().__init__(loc=package.loc) 148 self.name = name 149 self.package = package 150 151 def describe(self) -> str: 152 return f"namespace {self.name!r} is implied by {self.package.description}" 153 154 155@dataclass 156class SymbolConflictWithNamespaceError(DiagError): 157 decl: "PackageLevelDecl" 158 name: str 159 packages: list["PackageDecl"] 160 161 def __init__( 162 self, 163 decl: "PackageLevelDecl", 164 name: str, 165 packages: list["PackageDecl"], 166 ): 167 super().__init__(loc=decl.loc) 168 self.decl = decl 169 self.name = name 170 self.packages = packages 171 172 @override 173 def describe(self) -> str: 174 return f"declaration of {self.decl.description} conflicts with namespace {self.name!r}" 175 176 def notes(self): 177 for pkg in self.packages: 178 yield SymbolConflictWithNamespaceNote(self.name, pkg) 179 180 181@dataclass 182class TypeUsageError(DiagError): 183 ty: "Type" 184 185 def __init__(self, ty_ref: "TypeRefDecl"): 186 super().__init__(loc=ty_ref.loc) 187 pass 188 self.ty = ty_ref.maybe_resolved_ty 189 190 @override 191 def describe(self) -> str: 192 return f"{self.ty.signature} cannot be used in this context" 193 194 195@dataclass 196class EnumValueError(DiagError): 197 item: "EnumItemDecl" 198 enum: "EnumDecl" 199 200 def __init__(self, item: "EnumItemDecl", enum: "EnumDecl"): 201 super().__init__(loc=item.loc) 202 self.item = item 203 self.enum = enum 204 205 @override 206 def describe(self) -> str: 207 pass 208 return f"value of {self.item.description} ({self.item.value}) is conflict with {self.enum.description} ({self.enum.ty_ref.maybe_resolved_ty.signature})" 209 210 211@dataclass 212class DuplicateExtendsNote(DiagNote): 213 @override 214 def describe(self) -> str: 215 return "previously extended here" 216 217 218@dataclass 219class DuplicateExtendsWarn(DiagWarn): 220 iface: "IfaceDecl" 221 parent_iface: "IfaceDecl" 222 prev_loc: SourceLocation | None = field(kw_only=True) 223 224 @override 225 def describe(self) -> str: 226 return f"{self.parent_iface.description} is extended multiple times by {self.iface.description}" 227 228 @override 229 def notes(self): 230 if self.prev_loc: 231 yield DuplicateExtendsNote(loc=self.prev_loc) 232 233 234@dataclass 235class RecursiveReferenceNote(DiagNote): 236 decl: "TypeDecl" 237 238 def __init__( 239 self, 240 last: tuple["TypeDecl", "TypeRefDecl"], 241 ): 242 super().__init__(loc=last[1].loc) 243 self.decl = last[0] 244 245 @override 246 def describe(self) -> str: 247 return f"referenced by {self.decl.description}" 248 249 250@dataclass 251class RecursiveReferenceError(DiagError): 252 decl: "TypeDecl" 253 other: list[tuple["TypeDecl", "TypeRefDecl"]] 254 255 def __init__( 256 self, 257 last: tuple["TypeDecl", "TypeRefDecl"], 258 other: list[tuple["TypeDecl", "TypeRefDecl"]], 259 ): 260 super().__init__(loc=last[1].loc) 261 self.decl = last[0] 262 self.other = other 263 264 @override 265 def describe(self) -> str: 266 return f"cycle detected in {self.decl.description}" 267 268 @override 269 def notes(self): 270 for n in self.other: 271 yield RecursiveReferenceNote(n) 272 273 274class IgnoredFileReason(Enum): 275 IS_DIRECTORY = "subdirectories are ignored" 276 EXTENSION_MISMATCH = "unexpected file extension" 277 278 279@dataclass 280class IgnoredFileWarn(DiagWarn): 281 reason: IgnoredFileReason 282 283 @override 284 def describe(self) -> str: 285 return f"unrecognized file: {self.reason.value}" 286 287 288@dataclass 289class InvalidPackageNameError(DiagError): 290 name: str 291 292 @override 293 def describe(self) -> str: 294 return f"invalid package name {self.name!r}" 295 296 297@dataclass 298class AdhocNote(DiagNote): 299 msg: str 300 301 @override 302 def describe(self) -> str: 303 return self.msg 304 305 306@dataclass 307class AdhocWarn(DiagWarn): 308 msg: str 309 310 @override 311 def describe(self) -> str: 312 return self.msg 313 314 315@dataclass 316class AdhocError(DiagError): 317 msg: str 318 319 @override 320 def describe(self) -> str: 321 return self.msg 322 323 324@dataclass 325class AdhocFatalError(DiagFatalError): 326 msg: str 327 328 @override 329 def describe(self) -> str: 330 return self.msg